zoukankan      html  css  js  c++  java
  • [BZOJ2669][CQOI2012]局部极小值:DP+容斥原理

    分析

    题目要求有且只有一些位置是局部极小值。有的限制很好处理,但是只有嘛,嗯......

    考虑子集反演(话说这个其实已经算是超集反演了吧还叫子集反演是不是有点不太合适),枚举题目给出位置集合的所有超集,计算让这些位置成为局部极小值,而其他位置随意的方案数,这个可以通过DP,从小到大插入每个数解决。

    搜索加一些剪枝,然后就过了。。

    代码

    #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)
    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 LL MOD=12345678;
    
    int n,m,cnt;
    int dx[8]={-1,-1,-1,0,1,1,1,0},dy[8]={-1,0,1,1,1,0,-1,-1};
    int tot,X[10],Y[10],poscnt[1<<8],vis[5][10],tim;
    LL f[30][1<<8],ans;
    bool mp[5][10];
    
    LL solve(){
    	f[0][0]=1,tot=0;
    	rin(i,1,n){
    		rin(j,1,m){
    			if(mp[i][j]){
    				++tot;
    				X[tot]=i,Y[tot]=j;
    			}
    		}
    	}
    	rin(i,0,(1<<tot)-1){
    		poscnt[i]=n*m;
    		++tim;
    		rin(j,1,tot){
    			if((i>>(j-1))&1){
    				rin(k,0,7){
    					int xx=X[j]+dx[k],yy=Y[j]+dy[k];
    					if(xx<1||xx>n||yy<1||yy>m) continue;
    					if(vis[xx][yy]!=tim){
    						vis[xx][yy]=tim;
    						--poscnt[i];
    					}
    				}
    				if(vis[X[j]][Y[j]]!=tim){
    					vis[X[j]][Y[j]]=tim;
    					--poscnt[i];
    				}
    			}
    		}
    	}
    	rin(i,1,n*m){
    		rin(j,0,(1<<tot)-1){
    			if(__builtin_popcount(j)>i) continue;
    			f[i][j]=0;
    			if(poscnt[((1<<tot)-1)^j]>=i) f[i][j]=f[i-1][j]*(poscnt[((1<<tot)-1)^j]-i+1)%MOD;
    			rin(k,1,tot){
    				if((j>>(k-1))&1){
    					f[i][j]=(f[i][j]+f[i-1][j^(1<<(k-1))])%MOD;
    				}
    			}
    		}
    	}
    	return f[n*m][(1<<tot)-1];
    }
    
    void dfs(int x,int y){
    	if(x==n+1){ans=(ans+((cnt&1)==1?-1:1)*solve()%MOD+MOD)%MOD;return;}
    	bool flag=true;
    	rin(i,0,7){
    		int xx=x+dx[i],yy=y+dy[i];
    		if(xx<1||xx>n||yy<1||yy>m) continue;
    		if(mp[xx][yy]){flag=false;break;}
    	}
    	if(y==m) dfs(x+1,1);
    	else dfs(x,y+1);
    	if(!flag||mp[x][y]) return;
    	mp[x][y]=true;
    	++cnt;
    	if(y==m) dfs(x+1,1);
    	else dfs(x,y+1);
    	mp[x][y]=false;
    	--cnt;
    }
    
    int main(){
    	n=read(),m=read();
    	rin(i,1,n){
    		rin(j,1,m){
    			char ch=getchar();
    			while(ch!='X'&&ch!='.') ch=getchar();
    			if(ch=='X'){
    				mp[i][j]=true;
    				rin(k,0,7){
    					int xx=i+dx[k],yy=j+dy[k];
    					if(xx<1||xx>n||yy<1||yy>m) continue;
    					if(mp[xx][yy]){
    						printf("0
    ");
    						return 0;
    					}
    				}
    			}
    		}
    	}
    	dfs(1,1);
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Python学习笔记(四)多进程的使用
    Python学习笔记(三)多线程的使用
    windows无法安装msi文件
    标签传播算法
    信息论基础
    模块度Q
    HTTPS开发(SSL--用Tomcat服务器配置https双向认证)
    oracle 优化
    eclipse 界面开发--windowbuilder
    vba 读取数据库
  • 原文地址:https://www.cnblogs.com/ErkkiErkko/p/10429791.html
Copyright © 2011-2022 走看看