bzoj5153 [Wc2018]州区划分
2018-02-11 19:51
323 查看
题目链接
正解:子集和变换。
考场上只会暴力和$p=0$的情况,还只会$O(2^{n}*n^{3})$的。
然而这题题面出锅,导致考场上一直在卡裸暴力,后面的部分分没写了。。听$laofu$说$O(2^{n}*n^{3})$可以过。。
所以直接讲正解。。
我们假设每个城市可以在两个不同集合,那么可以把子集卷积变成或卷积。
我们只要记下当前总共有多少个点,于是考虑设$f[i][S]$表示$i$个点,集合为$S$的方案数。
最后的$f
[all]$就是答案,显然这个状态中的每个城市只会出现一次。
那么$f[i][S]=\sum f[j][T]*(\frac{sum[A]}{sum[S]})^{p}$,其中$A|T=S$,且$A$是一个合法集合。
可以把分母移项到左边,然后我们可以设$g[i][S]$表示如果$S$是一个合法集合,且$S$的位数为$i$,那么$g[i][S]=sum[S]^{p}$,否则为$0$。
那么$f[i][S]*sum[S]^{p}=\sum f[j][T]*g[i-j][A]$。注意到这个式子可以直接$FMT$以后点乘,再$IFMT$回来以后作除法得到,总复杂度为$O(2^{n}*n^{2})$。
感觉这道题其实并没有那么难,但是考场上被题面以及固定的套路给局限住了,所以并没有想到可以交换$dp$的两维状态从而优化复杂度。
正解:子集和变换。
考场上只会暴力和$p=0$的情况,还只会$O(2^{n}*n^{3})$的。
然而这题题面出锅,导致考场上一直在卡裸暴力,后面的部分分没写了。。听$laofu$说$O(2^{n}*n^{3})$可以过。。
所以直接讲正解。。
我们假设每个城市可以在两个不同集合,那么可以把子集卷积变成或卷积。
我们只要记下当前总共有多少个点,于是考虑设$f[i][S]$表示$i$个点,集合为$S$的方案数。
最后的$f
[all]$就是答案,显然这个状态中的每个城市只会出现一次。
那么$f[i][S]=\sum f[j][T]*(\frac{sum[A]}{sum[S]})^{p}$,其中$A|T=S$,且$A$是一个合法集合。
可以把分母移项到左边,然后我们可以设$g[i][S]$表示如果$S$是一个合法集合,且$S$的位数为$i$,那么$g[i][S]=sum[S]^{p}$,否则为$0$。
那么$f[i][S]*sum[S]^{p}=\sum f[j][T]*g[i-j][A]$。注意到这个式子可以直接$FMT$以后点乘,再$IFMT$回来以后作除法得到,总复杂度为$O(2^{n}*n^{2})$。
感觉这道题其实并没有那么难,但是考场上被题面以及固定的套路给局限住了,所以并没有想到可以交换$dp$的两维状态从而优化复杂度。
#include <bits/stdc++.h> #define il inline #define RG register #define ll long long #define rhl (998244353) #define N (1<<21|1) using namespace std; int fa[25],g[25],w ,cnt ,can ,inv[10005],n,m,p,all; int f[22] ,h[22] ; il int gi(){ RG int x=0,q=1; RG char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); if (ch=='-') q=-1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return q*x; } il int qpow(RG int a,RG int b){ if (!b) return 1; if (b==1) return a; return 1LL*a*a%rhl; } il void fmt(int *a){ for (RG int i=1;i<all;i<<=1) for (RG int j=0;j<all;++j){ if (j&i) a[j]+=a[j^i]; if (a[j]>=rhl) a[j]-=rhl; } return; } il void ifmt(int *a){ for (RG int i=1;i<all;i<<=1) for (RG int j=0;j<all;++j){ if (j&i) a[j]-=a[j^i]; if (a[j]<0) a[j]+=rhl; } return; } il int find(RG int x){ return fa[x]==x ? x : fa[x]=find(fa[x]); } int main(){ #ifndef ONLINE_JUDGE freopen("walk.in","r",stdin); freopen("walk.out","w",stdout); #endif n=gi(),m=gi(),p=gi(),all=1<<n,inv[1]=1; for (RG int i=1,u,v;i<=m;++i) u=gi()-1,v=gi()-1,g[u]|=1<<v,g[v]|=1<<u; for (RG int i=2;i<=3000;++i) inv[i]=1LL*(rhl-rhl/i)*inv[rhl%i]%rhl; for (RG int i=0;i<n;++i) w[1<<i]=gi(); fmt(w); for (RG int i=1;i<all;++i) cnt[i]=cnt[i>>1]+(i&1); for (RG int i=1,fg,lst;i<all;++i){ fg=0,lst=-1; for (RG int j=0;j<n;++j) fa[j]=j; for (RG int j=0;j<n;++j){ if (!(i>>j&1)) continue; for (RG int k=0,x,y;k<n;++k){ if (!(i>>k&1) || !(g[j]>>k&1)) continue; x=find(j),y=find(k); if (x!=y) fa[x]=y; } } for (RG int j=0;j<n;++j){ if (i>>j&1){ if (lst==-1) lst=find(j); else if (lst!=find(j)){ fg=1; break; } } if ((i>>j&1) && (cnt[g[j]&i]&1)){ fg=1; break; } } can[i]=fg; } for (RG int i=0;i<all;++i) if (can[i]) h[cnt[i]][i]=qpow(w[i],p); for (RG int i=1;i<=n;++i) fmt(h[i]); f[0][0]=1,fmt(f[0]); for (RG int i=1;i<=n;++i){ int *F=f[i]; for (RG int j=0;j<i;++j){ int *a=f[j],*b=h[i-j]; for (RG int s=0;s<all;++s) F[s]=(1LL*a[s]*b[s]+F[s])%rhl; } ifmt(F); for (RG int s=0;s<all;++s) F[s]=i==cnt[s]?1LL*F[s]*qpow(inv[w[s]],p)%rhl:0; if (i^n) fmt(F); } cout<<f [all-1]; return 0; }
相关文章推荐
- [WC 2018]州区划分
- [FMT] WC2018.州区划分
- [WC2018]州区划分
- 【WC2018】州区划分
- [WC2018]州区划分
- [WC2018]州区划分(子集卷积)
- 【UOJ348】【WC2018】州区划分 状压DP FWT
- 【BZOJ】1821: [JSOI2010]Group 部落划分 Group(最小生成树+贪心)
- 【BZOJ2594】【WC2006】水管局长数据加强版
- BZOJ1270: [BeijingWc2008]雷涛的小猫
- BZOJ2596 : [Wc2007]疯狂赛车
- 【bzoj2594】 Wc2006—水管局长数据加强版
- bzoj2018 [Usaco2009 Nov]农场技艺大赛
- 【BZOJ3052】【UOJ#58】【WC2013】糖果公园(树上莫队)
- BZOJ 1263: [SCOI2006]整数划分
- [BZOJ5249][多省联测2018]IIIDX
- [BZOJ5285][HNOI2018]寻宝游戏
- bzoj 5305: [Haoi2018]苹果树
- BZOJ1272: [BeiJingWc2008]Gate Of Babylon
- 【BZOJ】【3052】【WC2013】糖果公园