P3160 [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;
}
/*
*/