UOJ#348 州区划分
Posted huyufeifei
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UOJ#348 州区划分相关的知识,希望对你有一定的参考价值。
解:有一个很显然的状压......
就设f[s]表示选的点集为s的时候所有方案的权值和。
于是有f[s] = f[s t] * (sum[t] / sum[s])P。
这枚举子集是3n的。
然后发现这是子集卷积,参考资料。
于是就FWT搞一下...看代码
1 #include <bits/stdc++.h> 2 3 typedef long long LL; 4 const int N = 30, M = 2100000, MO = 998244353; 5 6 struct Edge { 7 int v, u; 8 }edge[N * N]; 9 10 int w[N], sum[M], cnt[M], n, P, lm, invsum[M], pw[M], in[N], fa[N]; 11 int f[N][M], g[N][M]; 12 bool vis[M]; 13 14 int find(int x) { 15 if(x == fa[x]) return x; 16 return fa[x] = find(fa[x]); 17 } 18 19 inline void out(int x) { 20 for(int i = 0; i < n; i++) { 21 printf("%d", (x >> i) & 1); 22 } 23 return; 24 } 25 26 inline void merge(int x, int y) { 27 fa[find(x)] = find(y); 28 return; 29 } 30 31 inline int qpow(int a, int b) { 32 int ans = 1; 33 while(b) { 34 if(b & 1) ans = 1ll * ans * a % MO; 35 a = 1ll * a * a % MO; 36 b = b >> 1; 37 } 38 return ans; 39 } 40 41 inline int pow(int x) { 42 return P ? (P == 1 ? x : 1ll * x * x % MO) : 1; 43 } 44 45 inline void FWT_or(int *a, int n, int f) { 46 for(int len = 1; len < n; len <<= 1) { 47 for(int i = 0; i < n; i += (len << 1)) { 48 for(int j = 0; j < len; j++) { 49 (a[i + len + j] += f * a[i + j]) %= MO; 50 if(a[i + len + j] < 0) a[i + len + j] += MO; 51 } 52 } 53 } 54 return; 55 } 56 57 int main() { 58 int m; 59 scanf("%d%d%d", &n, &m, &P); 60 61 for(int i = 1, x, y; i <= m; i++) { 62 scanf("%d%d", &edge[i].v, &edge[i].u); 63 } 64 for(int i = 1; i <= n; i++) scanf("%d", &w[i]); 65 lm = (1 << n) - 1; /// lm = 1111111111(2) 66 for(int i = 2; i <= lm; i++) pw[i] = pw[i >> 1] + 1; 67 for(int s = 1; s <= lm; s++) { 68 cnt[s] = cnt[s ^ (s & (-s))] + 1; 69 vis[s] = 0; 70 memset(in + 1, 0, n * sizeof(int)); 71 for(int i = 1; i <= n; i++) { 72 fa[i] = i; 73 } 74 for(int i = 1; i <= m; i++) { 75 if(((s >> (edge[i].v - 1)) & 1) && ((s >> (edge[i].u - 1)) & 1)) { 76 in[edge[i].v]++; 77 in[edge[i].u]++; 78 merge(edge[i].u, edge[i].v); 79 } 80 } 81 bool nol = 0; 82 int temp = 0; 83 for(int i = 1; i <= n; i++) { 84 if(in[i] & 1) { 85 vis[s] = 1; 86 } 87 if((s >> (i - 1)) & 1) { 88 (sum[s] += w[i]) %= MO; 89 if(!temp) { 90 temp = find(i); 91 } 92 else if(find(i) != temp) { 93 nol = 1; 94 } 95 } 96 } 97 if(nol) vis[s] = 1; 98 invsum[s] = qpow(sum[s], MO - 2); 99 if(vis[s]) { 100 g[cnt[s]][s] = pow(sum[s]); 101 } 102 } 103 104 f[0][0] = 1; 105 for(int i = 1; i <= n; i++) { 106 FWT_or(g[i], lm + 1, 1); 107 } 108 FWT_or(f[0], lm + 1, 1); 109 for(int i = 1; i <= n; i++) { 110 for(int j = 1; j <= i; j++) { 111 for(int s = 0; s <= lm; s++) { 112 (f[i][s] += 1ll * f[i - j][s] * g[j][s] % MO) %= MO; 113 } 114 } 115 FWT_or(f[i], lm + 1, -1); 116 for(int s = 0; s <= lm; s++) { 117 f[i][s] = 1ll * f[i][s] * pow(invsum[s]) % MO; 118 } 119 if(i < n) FWT_or(f[i], lm + 1, 1); 120 } 121 printf("%d ", f[n][lm]); 122 return 0; 123 }
以上是关于UOJ#348 州区划分的主要内容,如果未能解决你的问题,请参考以下文章