码迷,mamicode.com
首页 > 编程语言 > 详细

loj#2540. 「PKUWC2018」随机算法

时间:2018-12-31 10:26:39      阅读:236      评论:0      收藏:0      [点我收藏+]

标签:problem   ||   ++i   ble   排列   return   传送门   read   ==   

传送门

完了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]\times 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]='\n';
}
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\n",mul(dp[lim-1],inv[n]));
    return 0;
}

loj#2540. 「PKUWC2018」随机算法

标签:problem   ||   ++i   ble   排列   return   传送门   read   ==   

原文地址:https://www.cnblogs.com/bztMinamoto/p/10201424.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!