題解 洛谷 P5492 【[PKUWC2018]隨機演算法】
阿新 • • 發佈:2020-08-06
考慮到隨機排列來加入點等效每次隨機一個點,符合獨立集的限制就加入當前點集,不符合就不加入。
\(n\) 很小,考慮狀壓 \(DP\),設 \(f_S\) 為得到點集 \(S\) 內的點的最大獨立集的概率,\(siz_S\) 為點集 \(S\) 內的點的最大獨立集的大小。
\(DP\) 時列舉點集 \(S\) 中最後加入的一個點,將與該點相連的點都刪去,得到點集 \(T\),通過 \(T\) 來轉移。
先處理出 \(siz\):
\[siz_S = \max \left \{ siz_T +1\right \} \]
然後 \(f\) 通過 \(siz\) 的限制轉移即可:
\[f_S = \frac{1}{|S|} \sum_{siz_S=siz_T + 1} f_T \]
還要除 \(|S|\) 的原因是點集 \(S\) 中最後加入的一個點是等概率的。
複雜度為 \(O(n2^n)\)。
\(code:\)
#include<bits/stdc++.h> #define maxn 25 #define maxs 1050010 #define p 998244353 #define lowbit(x) (x&(-x)) using namespace std; typedef long long ll; template<typename T> inline void read(T &x) { x=0;char c=getchar();bool flag=false; while(!isdigit(c)){if(c=='-')flag=true;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} if(flag)x=-x; } int n,m,all; int e[maxn],cnt[maxs]; ll inv[maxn],siz[maxs],f[maxs]; void init() { inv[1]=1; for(int i=2;i<=n;++i) inv[i]=(p-p/i)*inv[p%i]%p; for(int i=1;i<=all;++i) cnt[i]=cnt[i-lowbit(i)]+1; } int main() { read(n),read(m),all=(1<<n)-1,init(); for(int i=1;i<=n;++i) e[i]=1<<(i-1),siz[1<<(i-1)]=1; for(int i=1;i<=m;++i) { int x,y; read(x),read(y); e[x]|=1<<(y-1),e[y]|=1<<(x-1); } for(int s=1;s<=all;++s) for(int i=1;i<=n;++i) if(s&(1<<(i-1))) siz[s]=max(siz[s],siz[s&(~e[i])]+1); f[0]=1; for(int s=1;s<=all;++s) { for(int i=1;i<=n;++i) if(s&(1<<(i-1))) if(siz[s]==siz[s&(~e[i])]+1) f[s]=(f[s]+f[s&(~e[i])])%p; f[s]=f[s]*inv[cnt[s]]%p; } printf("%lld",f[all]); return 0; }