loj#2540. 「PKUWC2018」随机算法

Posted bztminamoto

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了loj#2540. 「PKUWC2018」随机算法相关的知识,希望对你有一定的参考价值。

传送门

完了pkuwc咋全是dp怕是要爆零了……

(f(S))表示(S)的排列数,(S)为不能再选的点集(也就是选到独立集里的点和与他们相邻的点),(mx(S))表示(S)状态下对应的独立集大小,枚举点(i),如果(i)不在(S)里,分情况考虑,设(w[i])表示点(i)以及与之相邻的点,(T=S|w[i])(sz[S])表示二进制(S)有多少个(1),如果(mx[T]=mx[S]+1),那么[f[T]+=f[S] imes A_{n-sz[S]-1}^{sz[w[i]-(w[i]&S)]-1}]
上式的意思是,为了把(i)选进来,要把所有的与(i)相邻的点(除已经在(S)里的)都放到(i)的后面,那么共有(n-sz[S]-1)个位置,要放(sz[w[i]-(w[i]&S)]-1)个数,就是一个排列

如果(mx[T]<mx[S]+1),那么先把(f[T])清零,然后按上面更新就是了

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
    if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]='
';
}
const int N=(1<<20)+5,P=998244353;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
    R int res=1;
    for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x);
    return res;
}
int fac[25],inv[25],w[25],sz[N],dp[N],mx[N];
int n,m,u,v,lim;
inline int A(R int n,R int m){return mul(fac[n],inv[n-m]);}
int main(){
//  freopen("testdata.in","r",stdin);
    n=read(),m=read(),lim=(1<<n);
    while(m--)u=read()-1,v=read()-1,w[u]|=(1<<v),w[v]|=(1<<u);
    fp(i,0,n-1)w[i]|=(1<<i);
    fp(i,1,lim-1)sz[i]=sz[i>>1]+(i&1);
    fac[0]=inv[0]=fac[1]=inv[1]=1;
    fp(i,2,n)fac[i]=mul(fac[i-1],i);
    inv[n]=ksm(fac[n],P-2);
    fd(i,n-1,2)inv[i]=mul(inv[i+1],i+1);
    dp[0]=1;
    fp(S,0,lim-1)if(dp[S]){
        fp(i,0,n-1)if(!(S&(1<<i))){
            int T=S|w[i];
            if(mx[T]<mx[S]+1)mx[T]=mx[S]+1,dp[T]=0;
            if(mx[T]==mx[S]+1)dp[T]=add(dp[T],mul(dp[S],A(n-sz[S]-1,sz[w[i]-(w[i]&S)]-1)));
        }
    }printf("%d
",mul(dp[lim-1],inv[n]));
    return 0;
}

以上是关于loj#2540. 「PKUWC2018」随机算法的主要内容,如果未能解决你的问题,请参考以下文章

LOJ2540 [PKUWC2018] 随机算法 状压DP

Loj #2542. 「PKUWC2018」随机游走

loj#2542. 「PKUWC2018」随机游走(树形dp+Min-Max容斥)

THUWC2018 随机算法

Loj #2541「PKUWC2018」猎人杀

「PKUWC2018」随机算法