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;
    }
    
    
  • 相关阅读:
    go函数
    Linux 查看磁盘容量、查找大文件、查找大目录
    五分钟理解一致性哈希算法(consistent hashing)
    使用Java实现三个线程交替打印0-74
    Python实现IOC控制反转
    Wannafly挑战赛5 A珂朵莉与宇宙 前缀和+枚举平方数
    Yandex Big Data Essentials Week1 Scaling Distributed File System
    Yandex Big Data Essentials Week1 Unix Command Line Interface Processes managing
    Yandex Big Data Essentials Week1 Unix Command Line Interface File Content exploration
    Yandex Big Data Essentials Week1 Unix Command Line Interface File System exploration
  • 原文地址:https://www.cnblogs.com/hchhch233/p/10521482.html
Copyright © 2011-2022 走看看