Atcoder arc093F 状压DP+容斥原理

计数题都好神啊 ~     

但其实这道题也算是一个套路题吧,只是我没分析出来.....

code:

#include <cstdio> 
#include <algorithm>      
#define N 18   
#define ll long long 
#define mod 1000000007 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;        
int bin[N],f[N][1<<N],fac[1<<N],inv[1<<N],a[N];    
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; 
}
int C(int x,int y) { if(x<y) return 0; return (ll)fac[x]*inv[y]%mod*inv[x-y]%mod; }    
int count(int x) 
{ 
    int c=0;  
    while(x) { if(x&1) ++c;  x>>=1; }   
    return c;  
}
int main() 
{ 
    // setIO("input");  
    int i,j,n,m;  
    scanf("%d%d",&n,&m);                                    
    bin[0]=fac[0]=inv[0]=1; 
    for(i=1;i<=n;++i) bin[i]=bin[i-1]<<1;         
    for(i=1;i<=bin[n];++i) fac[i]=(ll)fac[i-1]*i%mod,inv[i]=qpow(fac[i],mod-2);
    for(i=1;i<=m;++i) scanf("%d",&a[i]);      
    sort(a+1,a+1+m); 
    f[m+1][0]=1;    
    int cnt=0; 
    for(i=m;i>=1;--i) 
    {
        for(j=0;j<bin[n];++j) 
        {

            f[i][j]=(ll)(f[i][j]+f[i+1][j])%mod;      
            int t=bin[n]-1-j;  // 共有 t 个空位置                    
            for(int k=0;bin[k]<bin[n];++k) 
            {  
                if(j&bin[k]||!f[i+1][j]) continue;        
                (f[i][j|bin[k]]+=((ll)f[i+1][j]*C(t-a[i]+1,bin[k]-1)%mod*fac[bin[k]]%mod)%mod)%=mod;  
            }         
        }
    }     
    int ans=0;   
    for(i=0;i<bin[n];++i) 
    {
        int d=(count(i)&1)?mod-1:1;          
        ans=(ll)(ans+(ll)f[1][i]*fac[bin[n]-1-i]%mod*d%mod)%mod;   
    }    
    ans=(ll)ans*bin[n]%mod;   
    printf("%d\n",ans); 
    return 0;
}

  

猜你喜欢

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