• Count


    题目大意

    给一个(n imes n(nleq 32))的网格,你需要选定(C)个格子,要求每行每列至少有一个格子,主对角线和副对角线至少有一个格子,有(k(kleq 7))个格子不能选,问方案数。

    题解

    容斥这个不用多说吧。。。

    首先对障碍点做容斥,其次对角线这个限制比较麻烦,不好和横竖同时处理。

    那么我们先对两条对角线做容斥,然后再去考虑行和列的限制。

    (f(i,j,k))表示有(i)行和(j)列是可以使用的,因为之前容斥的对角线的原因有(k)个格子不能选的方案数。

    这个可以用背包来解决,在进行背包转移的时候,枚举对称的两行两列,再(2^{16})枚举这两行两列的选择情况,根据对角线的容斥情况计算第三维的更新值。

    代码

    代码可以认为是抄的逆十字

    #include<bits/stdc++.h>
    #define N 1309
    #define M 33
    using namespace std;
    typedef long long ll;
    const int mod=10007;
    const int maxn=1200;
    int c[N][N],b[N];
    int x[N],y[N];
    int dp[M][M][M<<1],g[M][M][M<<1];
    int tagx[M],tagy[M];
    int n,k,m;
    inline ll rd(){
    	ll x=0;char c=getchar();bool f=0;
    	while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f?-x:x;
    }
    inline void MOD(int &x){x=x>=mod?x-mod:x;}
    inline void pre_work(){
    	for(int i=1;i<=maxn;++i)b[i]=b[i>>1]+(i&1);
    	c[0][0]=1;
    	for(int i=1;i<=maxn;++i){
    		c[i][0]=1;
    		for(int j=1;j<=i;++j)
    		    MOD(c[i][j]=c[i-1][j]+c[i-1][j-1]); 
    	}
    }
    int calc(int zh,int fu,int cnt){
        memset(dp,0,sizeof(dp));
        dp[0][0][0]=1;
        int siz=0; 
        for(int l=1,r=n;l<=r;l++,r--){
        	for(int i=0;i<=siz;++i)
        		for(int j=0;j<=siz;++j)
        		    for(int k=0;k<=siz*2;++k)if(dp[i][j][k]){
        		    	if(l!=r){
        		        	for(int i1=tagx[l];i1<=1;++i1)
        		        	    for(int i2=tagy[l];i2<=1;++i2)
        		        	         for(int i3=tagx[r];i3<=1;++i3)
    								     for(int i4=tagy[r];i4<=1;++i4){
    								     	int ni=i1+i3+i,nj=j+i2+i4,nk=k;
    								     	if(zh&&i1&&i2)nk++;
    								     	if(zh&&i3&&i4)nk++;
    										if(fu&&i1&&i4)nk++;
    										if(fu&&i2&&i3)nk++;
    										if(i1^i2^i3^i4)
    										     MOD(g[ni][nj][nk]+=mod-dp[i][j][k]);
    										else MOD(g[ni][nj][nk]+=dp[i][j][k]); 
    								 }
    					}
    					else{
    						for(int i1=tagx[l];i1<=1;++i1)
        		        	    for(int i2=tagy[l];i2<=1;++i2){
        		        	    	int ni=i+i1,nj=j+i2,nk=k;
        		        	    	if(i1&&i2&&(zh||fu))nk++;
        		        	    	if(i1^i2)MOD(g[ni][nj][nk]+=mod-dp[i][j][k]);
        		        	    	else MOD(g[ni][nj][nk]+=dp[i][j][k]);
        		        	    }
    					}       
    	            }
    		if(l==r)siz++;else siz+=2; 
    	    for(int i=0;i<=siz;++i)
    	        for(int j=0;j<=siz;++j)
    	            for(int k=0;k<=siz*2;++k){
    	            	dp[i][j][k]=g[i][j][k];
    	            	g[i][j][k]=0;
    	            }
    	}
    	int ans=0;
    	for(int i=0;i<=siz;++i)
    	    for(int j=0;j<=siz;++j)
    		    for(int k=0;k<=siz*2;++k){
    		    	if(i*j-k-cnt>=0){
    				     MOD(ans+=dp[i][j][k]*c[i*j-cnt-k][m]%mod);
    				}
    		    }
        return ans;
    }
    int solve(int s){
    	m-=b[s];
    	if(m<0){
    	   m+=b[s];
    	   return 0;
        }
    	int zh=0,fu=0;
    	for(int j=0;j<k;++j)if((1<<j)&s){
    		tagx[x[j]]=1;
    		tagy[y[j]]=1;
    		if(x[j]==y[j])zh=1;
    		if(x[j]+y[j]==n+1)fu=1;
    	}
    	int ans=calc(0,0,b[s]);
    	if(!zh)MOD(ans+=mod-calc(1,0,b[s]));
    	if(!fu)MOD(ans+=mod-calc(0,1,b[s]));
    	if(!zh&&!fu)MOD(ans+=calc(1,1,b[s]));
    	m+=b[s];
    	for(int j=0;j<k;++j)if((1<<j)&s){
    		tagx[x[j]]=0;
    		tagy[y[j]]=0;
    	}
    	return ans;
    }
    int main(){
    	pre_work(); 
    	n=rd();k=rd();m=rd();
    	for(int i=0;i<k;++i){
    		x[i]=rd();
    		y[i]=rd();
    	}
    	int ans=0;
    	for(int i=0;i<(1<<k);++i){
    		if(b[i]&1)MOD(ans+=mod-solve(i));
    		else MOD(ans+=solve(i));
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    
    
  • 相关阅读:
    应用js改变问章字体大小
    在北京实习的日子
    php算法
    SQL Server 查询处理中的各个阶段(SQL执行顺序)
    130 个你需要了解的 vim 命令
    分享一个检测用户是否用手机(Mobile)访问网站的 PHP 类
    使用apache自带日志分割模块rotatelogs,分割日志
    centos下lvs配置
    分享codeigniter框架,在zend studio 环境下的代码提示
    vi 常用命令
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/15087713.html
Copyright © 2020-2023  润新知