P3160 [CQOI2012] 局部极小值

[CQOI2012] 局部极小值 - 洛谷

题目详情 - [cqoi2012] 局部极小值 - BZOJ by HydroOJ

  • 又是我不擅长的找性质。性质:从小到大填数。当一个非局部最小值周围的所有局部最小值格子都被填了数时,这个位置才能填数。

  • 然后就很简单了,状压 \(dp\) 即可

    • 设计状态:\(dp_{i,S}\) 表示填了前 \(i\) 个数,局部最小值格子的状态为 \(S\) 的方案数

    • 转移:\(dp_{i,S}=\sum\limits_{x\in S} dp_{i-1,S-x}+k\times dp_{i-1,S}\),其中前面求和项指第 \(i\) 个数填给一个局部最小值格子的方案数,后面这项指填非局部最小值的方案数。当然注意真正实现的时候要判断每个非局部最小值格子能否被填,其中 \(k\) 为能被填的格子个数

  • 复杂度 \(O(2^cnmc)\),其中 \(c\) 为局部最小值格子个数,显然 \(c\leq 8\)

  • 注意到非局部最小值题目要求强制不满足条件,但我们这么算是可能出现满足情况的,因此考虑再套一个容斥。

  • 我们要枚举局部最小值格子的集合,因此复杂度会多一个 \(2^d\),其中 \(d\leq 8\)

  • 最终复杂度 \(O(2^{cd}nmc)\),但是跑不满(搜索=玄学)

/*
Coder: FOX_konata

tips:
	1. freopen
	2. the size of array
	3. long long
	4. test samples
	5. initialization
*/
#include <bits/stdc++.h>
using namespace std;
// #pragma GCC optimize(2)
#define pcn putchar('\n')
#define pcr putchar(' ')
#define ll long long
#define LL __int128
#define pii pair<int,int>
#define pli pair<ll,int>
#define pil pair<int,ll>
#define pll pair<ll,ll>
#define MP make_pair
#define fi first
#define se second
#define gsize(x) ((int)(x).size())
#define ckmin(a, b) (a=min(a,b))
#define ckmax(a, b) (a=max(a,b))
#define For(i,j,k) for(int i=(j),END##i=(k);i<=END##i;++i)
#define For__(i,j,k) for(int i=(j),END##i=(k);i>=END##i;--i)
#define Fore(i,j,k) for(int i=(j);i;i=(k))
#define deb(x) cerr<<"Line: "<<__LINE__<<", "<<#x<<"= "<<x<<"; \n"
namespace IO{template<typename T>T &read(T &num){num=0;T f=1;char c=' ';while(c<48||c>57)if((c=getchar())=='-')f=-1;while(c>=48&&c<=57)num=(num<<1)+(num<<3)+(c^48),c=getchar();return num*=f;}ll read(){ll num=0,f=1;char c=' ';while(c<48||c>57)if((c=getchar())=='-')f=-1;while(c>=48&&c<=57)num=(num<<1)+(num<<3)+(c^48),c=getchar();return num*f;}template<typename T>void Write(T x){if(x<0)putchar('-'),x=-x;if(x>9)Write(x/10);putchar('0'+x%10);return;}void putc(string s){int len=gsize(s)-1;For(i,0,len)putchar(s[i]);}template<typename T>void write(T x,string s="\0"){Write(x),putc(s);}};
using namespace IO;

//mt19937_64 rnd(chrono::steady_clock().now().time_since_epoch().count());
//ll random(ll l,ll r){ return (rnd()%(r-l+1))+l; }

/* ====================================== */
namespace Mian{

const int maxn=15;
const int maxnm=30;
const int max2n=(1<<9)+50;
const int tx[15]={0,1,0,-1,0,1,1,-1,-1};
const int ty[15]={0,0,1,0,-1,1,-1,1,-1};
const ll mod=12345678;
template<typename T1,typename T2>T1 Pls(T1 x,T2 y){x+=y;if(x>=mod)x-=mod;return x;}
template<typename T1,typename T2>T1 Dec(T1 x,T2 y){x-=y;if(x<0)x+=mod;return x;}
template<typename T1,typename T2>void ckpls(T1 &x,T2 y){x+=y;if(x>=mod)x-=mod;}
template<typename T1,typename T2>void ckdec(T1 &x,T2 y){x-=y;if(x<0)x+=mod;}
int n,m;
char a[maxn][maxn];
pii pos[maxnm];
ll dp[maxnm][max2n],ans;
bitset<maxn>bs[maxn];

ll calc(){
	int c=0;For(i,1,n)For(j,1,m)if(a[i][j]=='X')pos[++c]=MP(i,j);
	memset(dp,0,sizeof(dp));dp[0][0]=1;
	For(S,0,(1<<c)-1){
		For(i,1,n)bs[i].set();
		int cnt=n*m;
		For(i,0,c-1){
			if(!(S>>i&1)){
				For(j,0,8){
					int xx=pos[i+1].fi+tx[j],yy=pos[i+1].se+ty[j];
					if(xx<1||xx>n||yy<1||yy>m)continue;
					if(bs[xx][yy]){
						bs[xx][yy]=0;
						--cnt;
					}
				}
			}
		}
		For(i,1,n*m){
			dp[i][S]=(dp[i][S]+dp[i-1][S]*max(cnt-(i-1),0))%mod;
			For(j,0,c-1)if(S>>j&1)ckpls(dp[i][S],dp[i-1][S^(1<<j)]);
		}
	}
	return dp[n*m][(1<<c)-1];
}
void dfs(int x,int y,bool sign){
	if(x>n){sign?ckdec(ans,calc()):ckpls(ans,calc());return;}
	if(y>m)return dfs(x+1,1,sign);
	dfs(x,y+1,sign);
	bool flag=0;
	For(i,0,8){
		int xx=x+tx[i],yy=y+ty[i];
		if(xx<1||xx>n||yy<1||yy>m)continue;
		if(a[xx][yy]=='X'){flag=1;break;}
	}
	if(!flag)a[x][y]='X',dfs(x,y+1,sign^1),a[x][y]='.';
}

void mian(int TwT){
	read(n),read(m);For(i,1,n)scanf("%s",a[i]+1);
	For(x,1,n)For(y,1,m)if(a[x][y]=='X')For(i,1,8){
		int xx=x+tx[i],yy=y+ty[i];
		if(xx<1||xx>n||yy<1||yy>m)continue;
		if(a[xx][yy]=='X'){puts("0");return;}
	}
	dfs(1,1,0);
	write(ans,"\n");
}

void init(){

}

void BeginInit(){

}
};

int main() {

#ifdef LOCAL
	freopen("data.in","r",stdin);
//	freopen("data.out","w",stdout);
#else
//	freopen("data.in","r",stdin);
//	freopen("data.out","w",stdout);
#endif

	Mian::BeginInit();int T=1;
//	read(T);
	For(TwT, 1, T) Mian::init(),Mian::mian(TwT);

	return 0;
}
/*

*/
posted @ 2023-11-15 09:05  FOX_konata  阅读(6)  评论(0编辑  收藏  举报