[PKUWC2018]随机算法

Link

Solution

随便状压就可以了,设f[S]为答案,g[S]为S的最大独立集点数。对于每个S,枚举其点集内每个点作为p[1],那么选了这个点之后与其相连的所有点(记作r[i])都不能选,是个递归过程。
转移有 \(f_S=\frac{\sum\limits_{i\in S}f_{S-r[i]}\:\: \times \ [g_{S-r[i]}\:\: +1==g_S]}{|S|}\)

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read(){//be careful for long long!
    register int x=0,f=1;register char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
    while(isdigit(ch)){x=x*10+(ch^'0');ch=getchar();}
    return f?x:-x;
}

const int N=21,mod=998244353;
int n,m,rel[N],f[1<<N],g[1<<N],inv[N];

int main(){
    n=read(),m=read();inv[1]=1;
    for(int i=2;i<=n;++i)inv[i]=(mod-1ll*(mod/i)*inv[mod%i]%mod)%mod;
    for(int i=1;i<=m;++i){
	int u=read(),v=read();
	rel[u]|=(1<<(v-1)),rel[v]|=(1<<(u-1));
    }
    for(int i=1;i<=n;++i)rel[i]|=(1<<(i-1));
    f[0]=1;int all=(1<<n)-1;
    for(int s=1;s<=all;++s){
	int cnt=0;
	for(int i=1;i<=n;++i)
	    if((s>>(i-1))&1){
		++cnt;
		int t=s&(all^rel[i]);
		if(g[t]>=g[s])g[s]=g[t]+1,f[s]=f[t];
		else if(g[t]==g[s]-1)f[s]=(f[s]+f[t])%mod;
	    }
	f[s]=1ll*f[s]*inv[cnt]%mod;
    }
    printf("%d\n",f[all]);
    return 0;
}

posted @ 2019-12-11 17:35  Fruitea  阅读(142)  评论(0编辑  收藏  举报