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);
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址