JZOJ 6979. 【2021.02.03冬令营模拟】天各一方(DP)

JZOJ 6979. 【2021.02.03冬令营模拟】天各一方

题目大意

  • n n n个点组成的所有不同连通图中, 1 1 1 n n n的最短距离之和。
  • n ≤ 400 nle400 n400

题解

  • 很关键的一点是,因为是所有连边的方案,所以 1 1 1 n n n 1 1 1 2 2 2 1 1 1 3 3 3…… 1 1 1 n − 1 n-1 n1本质上都是相同的,所以答案可以转化为 1 1 1到剩下每个点的最短距离之和再除以 n − 1 n-1 n1

  • 试着把所有的点分层,距离即为它们层数的差值。初始时均在第 0 0 0层,通过DP使除了 1 1 1以外所有点下移。

  • f i , j f_{i,j} fi,j为当前确定好了 i i i个点,其中有 j j j个点确定了放在最后一层,而剩下的 n − i n-i ni此时也被移到了最后一层,但还将继续下移的方案数, g i , j g_{i,j} gi,j表示对应的总和。注意这里并不需要记录层数,因为它对转移无影响。

  • 转移时枚举下一层留下多少个 k k k,为了保证层数能对应距离,所以下一层只能和当前层连边,不能和上一层连边,同时层内可以自由连边,于是有:

  • f i , i + k = ∑ f i , j ∗ ( n − i k ) ∗ ( 2 j − 1 ) k ∗ 2 k ( k − 1 ) 2 f_{i,i+k}=sum f_{i,j}*{n-ichoose k}*(2^j-1)^k*2^{frac{k(k-1)}{2}} fi,i+k=fi,j(kni)(2j1)k22k(k1)

  • g i , i + k = ∑ ( g i , j + ( n − i ) ∗ f i , j ) ∗ ( n − i k ) ∗ ( 2 j − 1 ) k ∗ 2 k ( k − 1 ) 2 g_{i,i+k}=sum ig(g_{i,j}+(n-i)*f_{i,j}ig)*{n-ichoose k}*(2^j-1)^k*2^{frac{k(k-1)}{2}} gi,i+k=(gi,j+(ni)fi,j)(kni)(2j1)k22k(k1)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 410
#define ll long long
int c[N][N], e[N * N], s[N][N], P;
ll f[N][N], g[N][N];
ll ksm(ll x, ll y) {
	if(!y) return 1;
	ll l = ksm(x, y / 2);
	if(y % 2) return l * l % P * x % P;
	return l * l % P;
}
int main() {
	int n, i, j, k;
	scanf("%d%d", &n, &P);
	e[0] = 1;
	for(i = 1; i <= n * n; i++) e[i] = e[i - 1] * 2 % P;
	for(i = 0; i <= n; i++) {
		c[i][i] = c[i][0] = s[i][0] = 1;
		for(j = 1; j < i; j++) c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % P;
		for(j = 1; j <= n; j++) s[i][j] = (ll)s[i][j - 1] * (e[i] - 1) % P;
	}
	f[1][1] = 1, g[1][1] = 0;
	for(i = 1; i < n; i++) {
		for(j = 1; j <= i; j++) {
			for(k = 1; i + k <= n; k++) {
				ll t = (ll)c[n - i][k] * s[j][k] % P * e[k * (k - 1) / 2] % P;
				(f[i + k][k] += f[i][j] * t) %= P;
				(g[i + k][k] += g[i][j] * t + f[i][j] * t % P * (n - i)) %= P;
			}
		}
	}
	ll ans = 0;
	for(i = 1; i <= n; i++) (ans += g[n][i]) %= P;
	printf("%lld
", ans * ksm(n - 1, P - 2) % P);
	return 0;
}

自我小结

  • 对若干个等价的方案之一计数,可以先计算总和再除以相应的个数。
  • 和图或树有关的计数题可以从小数据入手,尽可能多地设出图的各种性质作为状态,尝试转移,最后再考虑优化。
哈哈哈哈哈哈哈哈哈哈
原文地址:https://www.cnblogs.com/LZA119/p/14437600.html