Comet OJ - Contest #11 F (arewell) (容斥+FST)

非常经典的 DAG 计数,由于不是完全图,所以要进行子集 DP.   

然后容斥一下发现可以写成 FST 的形式.  

code: 

#include <bits/stdc++.h> 
#define N 23    
#define ll long long 
#define mod 998244353 
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;    
int inv2,n,m,mp[N][N],bin[N],size[1<<N];   
int E[1<<N],dp[N][1<<N],g[N][1<<N];     
inline int qpow(int x,int y) 
{
    int tmp=1;   
    for(;y;y>>=1,x=(ll)x*x%mod)  
        if(y&1) 
            tmp=(ll)tmp*x%mod;  
    return tmp; 
}
inline int INV(int x) { return qpow(x,mod-2); }
void FWT(int *a,int len,int opt) 
{ 
    for(int i=1;i<len;i<<=1) 
        for(int j=0;j<len;j+=i<<1) 
            for(int k=0;k<i;++k) 
            {
                int x=a[j+k],y=a[j+k+i];        
                a[j+k]=(ll)(x+y)%mod,a[j+k+i]=(ll)(x-y+mod)%mod;   
                if(opt==-1) a[j+k]=(ll)inv2*a[j+k]%mod,a[j+k+i]=(ll)inv2*a[j+k+i]%mod;    
            }                        
}            
int main() 
{ 
    // setIO("input");        
    inv2=INV(2);   
    scanf("%d%d",&n,&m);   
    for(int i=1;i<=n+1;++i)  bin[i]=1<<(i-1);  
    for(int i=1;i<=m;++i) 
    {
        int x,y;
        scanf("%d%d",&x,&y);    
        mp[x][y]=mp[y][x]=1;   
    }        
    for(int S=1;S<bin[n+1];++S) 
    {   
        int fi;  
        for(int j=1;j<=n;++j) 
            if(S&bin[j]) { E[S]=E[S^bin[j]],fi=j; break; }
        size[S]=size[S^bin[fi]]+1;     
        for(int j=1;j<=n;++j) if(mp[fi][j]&&(S&bin[j])) ++E[S];           
    }              
    for(int i=1;i<bin[n+1];++i) 
    {  
        int d=(size[i]%2)==0?(mod-1):1;       
        g[size[i]][i]=(ll)d*INV(qpow(2,E[i]))%mod;         
    }    
    dp[0][0]=1;                          
    FWT(dp[0],bin[n+1],1);         
    for(int i=1;i<=n;++i) FWT(g[i],bin[n+1],1);            
    for(int sz=1;sz<=n;++sz) 
    {
        for(int i=1;i<=sz;++i)       
            for(int s=0;s<bin[n+1];++s) 
                (dp[sz][s]+=(ll)g[i][s]*dp[sz-i][s]%mod)%=mod;   
    }
    FWT(dp[n],bin[n+1],-1);           
    printf("%d\n",(ll)dp[n][bin[n+1]-1]*qpow(2,E[bin[n+1]-1])%mod*INV(qpow(3,E[bin[n+1]-1]))%mod); 
    return 0; 
}     

  

猜你喜欢

转载自www.cnblogs.com/guangheli/p/12822034.html