JZOJ 4532. 【清华夏令营2016模拟5.31】图样(动态规划)

Description:

小火车励志成为一名辣鸡出题人,但是要成为一名辣鸡出题人,代码必须跑得比谁都快,这样就能把他们都卡常数了!为了锻炼自己,他找到了一位长者——乐滋滋,乐滋滋说:“你啊,tooyoung!西方的哪一个国家我没有去过?”小火车坐在高高的骨灰旁边,听长者讲那西方的事情。
西方有n个国家,长者决定向西方的每个国家普及人生经验,但首先要让他们互通火车,第i个国家有一个权值Ai,修建连接第i个国家到第j个国家的铁路,需要付出Ai xor Aj(xor表示按位异或)的代价,长者希望代价总和尽量小(也就是选择一个最小生成树)。
但是在长者以前,没人去过西方,所以不知道每个国家的权值。但是我们知道每个国家的权值都是一个在0到2^m-1之间的随机整数,长者希望知道他所需要付出的代价的期望。
当然,答案是一个有理分数,为了避免精度误差长者需要你输出这个分数在模258280327(2*317+1,一个质数)意义下的值(如果不存在则输出-1)。

https://gmoj.net/senior/#main/show/4532

题解:

考虑知道每个点的点权怎么求最小生成树的权值和:

建出trie,对于trie的每个节点,如果它既有0儿子,又有1儿子,那么这两棵子树分别联通后,要找一条最小的边把它们连起来。

于是我们可以枚举这个节点的深度,再枚举它的左子树和右子树的大小,问题转换为:

\(x\)\(y\)\(k\)位二进制数,求它们之间的异或最小值。

这个可以dp,设\(f[x][y][k][u]\)\(x,y,k\)意义如上,\(u\)表示最小值\(\ge u\)的方案数。

枚举下一位怎么分开的,讨论下一位是0还是1,有点细节。

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

const int mo = 258280327;

ll ksm(ll x, ll y) {
	ll s = 1;
	for(; y; y /= 2, x = x * x % mo)
		if(y & 1) s = s * x % mo;
	return s;
}

const int N = 55;

const int M = 260;

int n, m;

ll c[M][M];

ll f[N][N][9][M];

int a2[9];

ll b[N];

void build(int n) {
	fo(i, 0, n) {
		c[i][0] = 1;
		fo(j, 1, i) c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mo;
	}
}

int main() {
	build(256);
	a2[0] = 1; fo(i, 1, 8) a2[i] = a2[i - 1] * 2;
	scanf("%d %d", &n, &m);
	fo(i, 0, n) fo(j, 0, n) fo(k, 0, m) if(!i || !j || !k) {
		ll s = 1;
		fo(u, 1, i + j) s = s * a2[k] % mo;
		ff(u, 0, a2[k]) f[i][j][k][u] = s;
	}
	fo(i, 1, n) fo(j, 1, n - i) fo(k, 1, m) {
		fo(ni, 0, i) fo(nj, 0, j) {
			int t = a2[k - 1];
			if((ni && nj) || ((i - ni) && (j - nj))) {
				t = 0;
			}
			ll xs = c[i][ni] * c[j][nj] % mo;
			ff(u, 0, a2[k - 1]) {
				if(t == 0) {
					f[i][j][k][u + t] = (f[i][j][k][u + t] + f[ni][nj][k - 1][u] * f[i - ni][j - nj][k - 1][u] % mo * xs) % mo;
				} else {
					f[i][j][k][u + t] = (f[i][j][k][u + t] + f[ni][j - nj][k - 1][u] * f[i - ni][nj][k - 1][u] % mo * xs) % mo;
				}
			}
		}
		ll s = f[i][j][k][a2[k - 1]];
		ff(u, 0, a2[k - 1]) f[i][j][k][u] = (f[i][j][k][u] + s) % mo;
	}
	ll ans = 0;
	fo(i, 1, m) {
		b[0] = 1;
		b[1] = a2[m] - a2[i];
		fo(j, 2, n) b[j] = b[j - 1] * b[1] % mo;
		fo(j, 1, n) fo(k, 1, n - j) {
			ll xs = c[n][j] * c[n - j][k] % mo * a2[m - i] % mo * b[n - j - k] % mo;
			ll xs2 = 1;
			fo(u, 1, j + k) xs2 = xs2 * a2[i - 1] % mo;
			ans = (ans + xs * a2[i - 1] % mo * xs2) % mo;
			ll s = 0;
			ff(u, 1, a2[i - 1]) s = (s + f[j][k][i - 1][u]) % mo;
			ans = (ans + xs * s) % mo;
		}
	}
	ll v = ksm(a2[m], n);
	pp("%lld\n", ans * ksm(v, mo - 2) % mo);
}
posted @ 2020-05-22 16:49  Cold_Chair  阅读(270)  评论(0编辑  收藏  举报