zoukankan      html  css  js  c++  java
  • [BZOJ2560]串珠子:状压DP+容斥原理

    分析

    为什么我去年6月做过这道题啊,估计当时抄的题解。

    具体做法就是令(f[S])表示保证连通点集(S)的方案数,(g[S])表示不保证连通点集(S)的方案数。

    容易想到:

    [g[S]=sum f[S-T] imes g[T] ]

    这里的(T)(S)去掉一个点后得到的集合的所有非空子集。

    然后就有:

    [f[S]=cnt[S]-g[S] ]

    其中(cnt[S])表示在点集(S)中随意连边的的方案数,可以在过程中递推算出。

    计算出(f[S])之后,需要(g[S]=g[S]+f[S])

    代码

    #include <bits/stdc++.h>
    #define rin(i,a,b) for(register int i=(a);i<=(b);++i)
    #define irin(i,a,b) for(register int i=(a);i>=(b);--i)
    #define trav(i,a) for(register int i=head[a];i;i=e[i].nxt)
    #define lowbit(x) ((x)&(-(x)))
    #define r (s^t)
    typedef long long LL;
    using std::cin;
    using std::cout;
    using std::endl;
    
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    
    const int MAXN=20;
    const LL MOD=1e9+7;
    
    int n;
    LL c[MAXN][MAXN];
    LL f[1<<16],g[1<<16],cnt[1<<16];
    
    inline int calc(int x,int y){
    	int xx=0,yy=0;LL ret=1;
    	while(x){
    		++xx;
    		x>>=1;
    	}
    	while(y){
    		++yy;
    		if(y&1) ret=(ret*(c[xx][yy]+1))%MOD;
    		y>>=1;
    	}
    	return ret;
    }
    
    int main(){
    	n=read();
    	rin(i,1,n) rin(j,1,n) c[i][j]=read(),f[1<<(i-1)]=g[1<<(i-1)]=1,cnt[1<<(i-1)]=1;
    	rin(s,1,(1<<n)-1){
    		if(__builtin_popcount(s)<=1) continue;
    		int x=lowbit(s),y=(s^x);
    		cnt[s]=cnt[y]*calc(x,s)%MOD;
    		for(register int t=y;t;t=((t-1)&y)) g[s]=(g[s]+f[r]*g[t])%MOD;
    		f[s]=(cnt[s]-g[s]+MOD)%MOD;
    		g[s]=(g[s]+f[s])%MOD;
    	}
    	printf("%lld
    ",f[(1<<n)-1]);
    	return 0;
    }
    
  • 相关阅读:
    学员操作——隔行变色
    jQuery基础及选择器(1)
    学员操作——组合继承
    JavaScript面向对象
    学员操作——创建继承person的student子类
    学员操作——flower函数
    JavaScript操作DOM(2)
    JavaScript操作DOM(1)
    学员操作——制作秒表定时器
    学员操作——制作5s关闭广告
  • 原文地址:https://www.cnblogs.com/ErkkiErkko/p/10409013.html
Copyright © 2011-2022 走看看