[WC2018]州区划分(状压DP+FWT/FMT)

很裸的子集反演模板题,套上一些莫名其妙的外衣。

先预处理每个集合是否合法,再作显然的状压DP。然后发现可以写成子集反演的形式,直接套模板即可。

子集反演可以看这里

子集反演的过程就是多设一维代表集合大小,再FMT处理集合并卷积。

然而我的FMT常数过大,而并卷积又可以用FWT实现,于是就写FWT了。(实际上就三行的区别)

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 5 using namespace std;
 6 
 7 const int N=22,mod=998244353;
 8 int n,m,p,x,y,mp[N][N],w[N],fa[N],a[N],d[N],sm[1<<N],sz[1<<N],lg[1<<N],f[N][1<<N],g[N][1<<N];
 9 
10 int pow(int a,int b){ return b==0 ? 1 : (b==1 ? a : 1ll*a*a%mod); }
11 int get(int x){ return (fa[x]==x) ? x : fa[x]=get(fa[x]); }
12 
13 int ksm(int a,int b){
14     int res=1;
15     for (; b; a=1ll*a*a%mod,b>>=1)
16         if (b & 1) res=1ll*res*a%mod;
17     return res;
18 }
19 
20 void init(){
21     rep(i,0,n) lg[1<<i]=i;
22     rep(S,1,(1<<n)-1){
23         int t=S&-S,tot=0;
24         sm[S]=sm[S^t]+w[lg[t]]; sz[S]=sz[S^t]+1;
25         for (int i=S; i; i=i^(i&-i)) a[++tot]=lg[i&-i];
26         rep(i,1,tot) fa[a[i]]=a[i],d[a[i]]=0;
27         rep(i,1,tot){
28             rep(j,1,tot) if (mp[a[i]][a[j]]) d[a[i]]^=1,fa[get(a[i])]=get(a[j]);
29             if (d[a[i]]) { g[sz[S]][S]=1; break; }
30         }
31         int f=get(a[1]);
32         rep(i,2,tot) if (f!=get(a[i])){ g[sz[S]][S]=1; break; }
33     }
34     rep(i,0,(1<<n)-1) sm[i]=pow(sm[i],p),g[sz[i]][i]=1ll*g[sz[i]][i]*sm[i]%mod;
35 }
36 
37 void FMT(int a[],int n,int f){
38     for (int i=1; i<n; i<<=1)
39         rep(j,0,n-1) if (j&i) a[j]=(a[j]+1ll*f*a[j^i]+mod)%mod;
40 }
41 
42 void solve(){
43     f[0][0]=1; FMT(f[0],1<<n,1);
44     rep(i,0,n) FMT(g[i],1<<n,1);
45     rep(i,1,n){
46         rep(j,0,(1<<n)-1) rep(x,0,i-1)
47             f[i][j]=(f[i][j]+1ll*f[x][j]*g[i-x][j])%mod;
48         FMT(f[i],1<<n,-1);
49         rep(j,0,(1<<n)-1)
50             if (sz[j]==i) f[i][j]=1ll*f[i][j]*ksm(sm[j],mod-2)%mod; else f[i][j]=0;
51         FMT(f[i],1<<n,1);
52     }
53     FMT(f[n],1<<n,-1); printf("%d\n",f[n][(1<<n)-1]);
54 }
55 
56 int main(){
57     scanf("%d%d%d",&n,&m,&p);
58     rep(i,1,m) scanf("%d%d",&x,&y),mp[x-1][y-1]=mp[y-1][x-1]=1;
59     rep(i,0,n-1) scanf("%d",&w[i]);
60     init(); solve();
61     return 0;
62 }
FMT(TLE)

FWT:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 5 using namespace std;
 6 
 7 const int N=22,mod=998244353;
 8 int n,m,p,x,y,mp[N][N],w[N],fa[N],a[N],d[N],sm[1<<N],sz[1<<N],lg[1<<N],f[N][1<<N],g[N][1<<N];
 9 
10 int pow(int a,int b){ return b==0 ? 1 : (b==1 ? a : 1ll*a*a%mod); }
11 int get(int x){ return (fa[x]==x) ? x : fa[x]=get(fa[x]); }
12 
13 int ksm(int a,int b){
14     int res=1;
15     for (; b; a=1ll*a*a%mod,b>>=1)
16         if (b & 1) res=1ll*res*a%mod;
17     return res;
18 }
19 
20 void init(){
21     rep(i,0,n) lg[1<<i]=i;
22     rep(S,1,(1<<n)-1){
23         int t=S&-S,tot=0;
24         sm[S]=sm[S^t]+w[lg[t]]; sz[S]=sz[S^t]+1;
25         for (int i=S; i; i=i^(i&-i)) a[++tot]=lg[i&-i];
26         rep(i,1,tot) fa[a[i]]=a[i],d[a[i]]=0;
27         rep(i,1,tot){
28             rep(j,1,tot) if (mp[a[i]][a[j]]) d[a[i]]^=1,fa[get(a[i])]=get(a[j]);
29             if (d[a[i]]) { g[sz[S]][S]=1; break; }
30         }
31         int f=get(a[1]);
32         rep(i,2,tot) if (f!=get(a[i])){ g[sz[S]][S]=1; break; }
33     }
34     rep(i,0,(1<<n)-1) sm[i]=ksm(sm[i],p),g[sz[i]][i]=1ll*g[sz[i]][i]*sm[i]%mod;
35 }
36 
37 void FWT(int a[],int n,int f){
38     for (int i=2; i<=n; i<<=1)
39         for (int j=0; j<n; j+=i)
40             rep(k,j,j+(i>>1)-1)
41                 a[k+(i>>1)]=(1ll*a[k+(i>>1)]+f*a[k]+mod)%mod;
42 }
43 
44 void solve(){
45     f[0][0]=1; FWT(f[0],1<<n,1);
46     rep(i,0,n) FWT(g[i],1<<n,1);
47     rep(i,1,n){
48         rep(j,0,(1<<n)-1) rep(x,0,i-1)
49             f[i][j]=(f[i][j]+1ll*f[x][j]*g[i-x][j])%mod;
50         FWT(f[i],1<<n,-1);
51         rep(j,0,(1<<n)-1)
52             if (sz[j]==i) f[i][j]=1ll*f[i][j]*ksm(sm[j],mod-2)%mod; else f[i][j]=0;
53         FWT(f[i],1<<n,1);
54     }
55     FWT(f[n],1<<n,-1); printf("%d\n",f[n][(1<<n)-1]);
56 }
57 
58 int main(){
59     scanf("%d%d%d",&n,&m,&p);
60     rep(i,1,m) scanf("%d%d",&x,&y),mp[x-1][y-1]=mp[y-1][x-1]=1;
61     rep(i,0,n-1) scanf("%d",&w[i]);
62     init(); solve();
63     return 0;
64 }
posted @ 2019-01-20 22:47  HocRiser  阅读(254)  评论(0编辑  收藏  举报