[WC2018]州区划分 [DP+FWT]

Posted qq62c30ac77b2a7

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[WC2018]州区划分 [DP+FWT]相关的知识,希望对你有一定的参考价值。

​传送门​

考虑朴素的DP, 令 [WC2018]州区划分 表示把集合S分为若干个集合的不满意度之和, [WC2018]州区划分 表示集合 s 的人口和

[WC2018]州区划分

发现是一个子集卷积

[WC2018]州区划分

对于第二个限制,我们可以构造一个 [WC2018]州区划分, 只有当 popcnt(s) = i 时才有值

然后按 i 从小到大处理,然后FWT, 每次把 popcnt(s) != i 的位置清零

#include<bits/stdc++.h>
#define N (1<<21)+5
#define M 23
using namespace std;
typedef long long ll;
const int Mod = 998244353;
int read()
int x = 0, f = 1; char ch = 0;
while(!isdigit(ch)) ch = getchar(); if(ch == -) f = -1;
while(isdigit(ch)) x = x*10 + (ch-0), ch = getchar();
return x * f;

ll add(ll a, ll b) return a + b >= Mod ? a + b - Mod : a + b;
ll dec(ll a, ll b) return a - b < 0 ? a - b + Mod : a - b;
ll mul(ll a, ll b) return (a * b) % Mod;
int n, m, p, len;
ll w[N], sum[N], inv[N], f[M][N], g[M][N];
int bin[N], mp[M][M];
int fa[N], du[N];
ll power(ll a, ll b) ll ans = 1;
for(;b;b>>=1) if(b&1) ans = mul(ans, a); a = mul(a, a);
return ans;

int find(int x) return (x == fa[x]) ? x : fa[x] = find(fa[x]);
bool check(int S)
for(int i = 1; i <= n; i++) fa[i] = i, du[i] = 0;
int cnt = 0;
for(int i = 1; i <= n; i++)
if((1<<(i-1)) & S)
sum[S] += w[i];
for(int j = i+1; j <= n; j++)
if((mp[i][j] || mp[j][i]) && ((1<<(j-1)) & S))
du[i]++, du[j]++;
int fx = find(i), fy = find(j);
if(fx^fy) fa[fx] = fy, cnt++;




if(p == 0) sum[S] = 1; if(p == 2) sum[S] = mul(sum[S], sum[S]);
if(cnt != bin[S]-1) return true;
for(int i = 1; i <= n; i++)
if(((1<<(i-1)) & S) && du[i]&1) return true;
return false;

void DFT(ll *a)
for(int i = 1; i <= len; i <<= 1)
for(int j = 0; j <= len; j += (i<<1))
for(int k = 0; k < i; k++)
a[k+j+i] = add(a[k+j+i], a[k+j]);

void IDFT(ll *a)
for(int i = 1; i <= len; i <<= 1)
for(int j = 0; j <= len; j += (i<<1))
for(int k = 0; k < i; k++)
a[k+j+i] = dec(a[k+j+i], a[k+j]);

int main()
n = read(); m = read(); p = read(); len = (1<<n) - 1;
for(int i = 1; i <= m; i++) mp[read()][read()] = 1;
for(int i = 1; i <= n; i++) w[i] = read();
for(int i = 0; i <= len; i++) bin[i] = bin[i>>1] + (i&1);
for(int i = 1; i <= len; i++)
g[bin[i]][i] = check(i) ? sum[i] : 0;
inv[i] = power(sum[i], Mod-2);

for(int i = 0; i <= n; i++) DFT(g[i]);
f[0][0] = 1; DFT(f[0]);
for(int i = 1; i <= n; i++)
for(int j = 0; j <= i-1; j++) for(int k = 0; k <= len; k++)
f[i][k] = add(f[i][k], mul(f[j][k], g[i-j][k]));
IDFT(f[i]);
for(int j = 0; j <= len; j++) f[i][j] = (bin[j]^i) ? 0 : mul(f[i][j], inv[j]);
if(i^n) DFT(f[i]);
cout << f[n][len]; return 0;

 


以上是关于[WC2018]州区划分 [DP+FWT]的主要内容,如果未能解决你的问题,请参考以下文章

WC2018 州区划分

[WC2018]州区划分

uoj348WC2018州区划分

[UOJ#348][WC2018]州区划分

[WC2018]州区划分

[WC 2018]州区划分