zoukankan      html  css  js  c++  java
  • P3160 [CQOI2012]局部极小值

    题目

    P3160 [CQOI2012]局部极小值

    一眼就是状压,接下来就不知道了(qwq)

    做法

    我们能手玩出局部小值最多差不多是(8,9)个的样子,(dp_{i,j})为填满(1~i)数字,局部小值的状态为(j)

    (k)个局部极小值填(i)(dp[i][j]=(dp[i][j]+dp[i-1][j^(1<<k-1)])%p)

    不填在局部极小值,显然有些地方不能填(i)的,首先还没填的局部极小值不填,其周围也不能填(填(i)后后面再填比不符合局部极小值)
    我们预处理出每种状态不能填时的位置:(dp[i][j]=(dp[i][j]+dp[i-1][j]*max(num[j]-i+1,0))%p)

    一顿操作后发现WA了,我们得到的局部极小值可能不是恰好是给出的(X)(更多)

    容斥原理:Ans=至少多0个极小值-至少多1个极小值+至少多两个极小值......

    理解:至少多0个((x,x+1,x+2,x+3...)-k(x+1,x+2,x+3...))其中(k)为某些值的系数
    填了至少多0个极小值后,有多填的部分那就得减去至少多1个极小值,至少多1个极小值的位置也有很多,就会有一些位置减掉的系数为(k>1),就要又加上

    (dfs)时加上能被多余的极小值填上的地方换成'X',然后多次做(dp)

    My complete code

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    typedef long long LL;
    const int maxn=31;
    const int p=12345678;
    const int dx[8]={-1,-1,-1,0,1,1,1,0},dy[8]={-1,0,1,1,1,0,-1,-1};
    int n,m,tot;
    LL ans;
    int x[maxn],y[maxn],num[1<<9],dp[maxn][1<<9];
    bool visit[maxn][maxn];
    char s[maxn][maxn];
    inline int Solve(){
    	tot=0;
    	for(int i=1;i<=n;++i)
    	    for(int j=1;j<=m;++j)
    	        if (s[i][j]=='X')
    	            x[++tot]=i,
    				y[tot]=j;
    	int Up=1<<tot;
    	for(int i=0;i<Up;i++){
    	 	int cnt(0);
    	 	memset(visit,0,sizeof(visit));
    		for(int j=1;j<=tot;++j)
    	 	    if(!((i>>(j-1))&1)){
    	 	  	    visit[x[j]][y[j]]=1;
    	 	  	    for(int k=0;k<8;++k){
    	 	  	 	    int xx=x[j]+dx[k];
    	 	  	 	    int yy=y[j]+dy[k];
    	 	  	 	    if(xx>0&&yy>0&&xx<=n&&yy<=m)
    	 	  	 	        visit[xx][yy]=1;
    			    }
    		    }
    		for(int j=1;j<=n;++j)
    		    for(int k=1;k<=m;++k) 
    		        if(visit[j][k])  
    				    ++cnt;
    		num[i]=n*m-cnt;
    	}
    	memset(dp,0,sizeof(dp));
    	dp[0][0]=1;
    	for(int i=1;i<=n*m;++i)
    	    for(int j=0;j<Up;++j){
    	  	    dp[i][j]=(dp[i][j]+dp[i-1][j]*max(num[j]-i+1,0))%p;
    	  	    for(int k=1;k<=tot;k++)
    	  	        if(j&(1<<(k-1)))
    	  	            dp[i][j]=(dp[i][j]+dp[i-1][j^(1<<k-1)])%p;
    	    }
    	return dp[n*m][Up-1];
    }
    void Dfs(int x,int y,int k){
    	if(y==m+1){
    	    Dfs(x+1,1,k);
    	 	return;
    	}
    	if(x==n+1){
    		ans=(ans+(((k&1)==0)?1:-1)*Solve()+p)%p;
    	 	return;
    	}
    	Dfs(x,y+1,k);
    	if(s[x][y]!='X'){
    	    bool f=true;
    	    for(int i=0;i<8;i++)
    	        if(s[x+dx[i]][y+dy[i]]=='X'){
    	  	        f=false;
    	  	        break;
    	        }
    	    if(f){
    	        s[x][y]='X',
    	        Dfs(x,y+1,k+1),
    	        s[x][y]='.';
    	    }
    	}
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
        	scanf(" %s",s[i]+1);
    	Dfs(1,1,0);
    	printf("%lld
    ",ans);
    	return 0;
    }
    /*
    5 5
    .....
    ...X.
    .X...
    .....
    ....X
    */
    
  • 相关阅读:
    内存区间poj 1840
    旋转实现iOS(iPhone/iPad) 屏幕旋转响应函数的缺点与窗口大小位置调整,以及解决办法
    文件模式JAVASE16IO流_3
    配置修改postgresql streaming replication
    查看字段postgresql pg_buffercache
    窗体方法VB.NET设置控件和窗体的显示级别
    流量最小HDU 3491 最小割
    方法返回javascript学习实录 之二(数组操作等等utils) 刘啸尘
    配置路由器静态路由配置
    任务问题Oracle 技术支持之现场优化的思维路径
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/10262116.html
Copyright © 2011-2022 走看看