zoukankan      html  css  js  c++  java
  • 【CQOI2012】局部极小值

    【CQOI2012】局部极小值

    Description

      有一个(n)(m)列的整数矩阵,其中(1)(nm)之间的每个整数恰好出现一次。如果一个格子比所有相邻格子(相邻是指有公共边或公共顶点)都小,我们说这个格子是局部极小值。
      给出所有局部极小值的位置,你的任务是判断有多少个可能的矩阵。

    答案对(123456789)取模。

    (1leq nleq 4,1leq mleq 7)

    样例输入:

    1 3
    .X.

    样例输出:

    2

    我们可以发现一张图上的最小值点最多(8)个。于是我们找到所有的最小值点以及与这些点的所有相邻点。

    我们考虑从(1)(nm)将每个数字填入一个格子中。显然一个格子((x,y))只有在((x,y))周围的最小值点都已经填充了数字的时候它才能填充。

    我们设(size_{S})表示最小值填充的情况为(S)的时候有多少非最小值点可以填充。

    我们考虑从(nm)(1)倒着枚举每个数(i),然后在枚举集合(S)表示(i+1)(nm)中已经填充了(S)集合中的最小值。然后用组合数搞一搞就好了。

    但是我们会发现一个问题,我们算出的答案中的最小值点可能不止题目中给定的点,这种情况是要舍去的。所以我们就(dfs)枚举所有可能的最小值点的情况,然后容斥就行了。

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define N 10
    #define M 10
    
    using namespace std;
    inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
    
    const ll mod=12345678;
    int n,m;
    char mp[N][N];
    #define pr pair<int,int>
    #define mp(a,b) make_pair(a,b)
    
    vector<pr>mn;
    int q[15];
    ll f[1<<8],g[1<<8];
    int num;
    ll fac[N*M];
    ll C[N*M][N*M];
    int sta[N][M];
    int dx[]={1,1,0,-1,-1,-1,0,1},dy[]={0,-1,-1,-1,0,1,1,1};
    int size[1<<8];
    int bin[1<<8];
    
    bool vis[N][M];
    
    ll DP() {
    	memset(sta,0,sizeof(sta));
    	memset(f,0,sizeof(f));
    	memset(size,0,sizeof(size));
    	int cnt=0;
    	for(int i=0;i<mn.size();i++) {
    		int x=mn[i].first,y=mn[i].second;
    		for(int j=0;j<8;j++) {
    			int a=x+dx[j],b=y+dy[j];
    			sta[a][b]|=1<<cnt;
    		}
    		cnt++;
    	}
    	if(!cnt) return fac[n*m];
    	for(int T=0;T<1<<cnt;T++) {
    		for(int i=1;i<=n;i++) {
    			for(int j=1;j<=m;j++) {
    				if(sta[i][j]&&(sta[i][j]&T)==sta[i][j]) {
    					size[T]++;
    				}
    			}
    		}
    	}
    	ll ans=0;
    	f[0]=1;
    	for(int i=n*m;i>=1;i--) {
    		memset(g,0,sizeof(g));
    		for(int T=0;T<1<<cnt;T++) {
    			if(!f[T]) continue ;
    			int res=((1<<cnt)-1)^T;
    			for(int j=0;j<cnt;j++) {
    				if(T>>j&1) continue ;
    				int now=size[res]-size[res^(1<<j)];
    				int emp=n*m-i-bin[T]-(size[(1<<cnt)-1]-size[res]);
    				if(emp>=now) {
    					(g[T|(1<<j)]+=C[emp][now]*fac[now]%mod*f[T])%=mod;
    				}
    			}
    		}
    		for(int T=0;T<1<<cnt;T++) (f[T]+=g[T])%=mod;
    	}
    	ans=f[(1<<cnt)-1];
    	return ans*fac[n*m-size[(1<<cnt)-1]-bin[(1<<cnt)-1]]%mod;
    }
    
    ll dfs(int x,int y,ll flag) {
    	if(x>n) {
    		ll tem=DP();
    		return DP()*flag%mod;
    	}
    	if(y>m) return dfs(x+1,1,flag);
    	else {
    		ll ans=0;
    		if(!vis[x][y]) {
    			int tag=1;
    			for(int i=0;i<8;i++) {
    				int a=x+dx[i],b=y+dy[i];
    				if(vis[a][b]) tag=0; 
    			}
    			if(tag) {
    				vis[x][y]=1;
    				mn.push_back(mp(x,y));
    				(ans+=dfs(x,y+1,flag*(mod-1)%mod))%=mod;
    				vis[x][y]=0;
    				mn.pop_back();
    			}
    		}
    		(ans+=dfs(x,y+1,flag))%=mod;
    		return ans;
    	}
    }
    
    void out(int S) {
    	for(int i=0;i<mn.size();i++) cout<<(S>>i&1);
    	cout<<"
    ";
    }
    
    int main() {
    	n=Get(),m=Get();
    	fac[0]=1;
    	for(int i=1;i<=n*m;i++) fac[i]=fac[i-1]*i%mod;
    	for(int i=0;i<=n*m;i++)
    		for(int j=0;j<=i;j++)
    			C[i][j]=(!j||i==j)?1:(C[i-1][j-1]+C[i-1][j])%mod;
    	for(int S=0;S<1<<8;S++) 
    		for(int i=0;i<8;i++) bin[S]+=(S>>i&1);
    		
    	for(int i=1;i<=n;i++) {
    		scanf("%s",mp[i]+1);
    	}
    	int flag=0;
    	for(int i=1;i<=n;i++) {
    		for(int j=1;j<=m;j++) {
    			if(mp[i][j]=='X') {
    				mn.push_back(mp(i,j));
    				vis[i][j]=1;
    				if(mp[i-1][j]=='X'||mp[i][j-1]=='X'||mp[i-1][j-1]=='X'||mp[i-1][j+1]=='X') {
    					flag=1;
    				}
    			}
    		}
    	}
    	if(flag) return cout<<0,0;
    	cout<<dfs(1,1,1);
    	return 0;
    }
    
    
  • 相关阅读:
    Pandas速查手册中文版
    MySQL-增删改查
    主从复制-常见问题
    redis-主从复制
    高级数据类型-GEO
    高级数据类型-HyperLogLog
    高级数据类型-bitmaps
    redis-redis.conf基础配置
    删除策略--逐出策略
    删除策略-过期数据
  • 原文地址:https://www.cnblogs.com/hchhch233/p/10521482.html
Copyright © 2011-2022 走看看