题解 洛谷 P5492 【[PKUWC2018]随机算法】

考虑到随机排列来加入点等效每次随机一个点,符合独立集的限制就加入当前点集,不符合就不加入。

(n) 很小,考虑状压 (DP),设 (f_S) 为得到点集 (S) 内的点的最大独立集的概率,(siz_S) 为点集 (S) 内的点的最大独立集的大小。

(DP) 时枚举点集 (S) 中最后加入的一个点,将与该点相连的点都删去,得到点集 (T),通过 (T) 来转移。

先处理出 (siz)

[siz_S = max left { siz_T +1 ight } ]

然后 (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;
}
原文地址:https://www.cnblogs.com/lhm-/p/13444283.html