给定一个n∗m的矩阵,标记出其中的局部极小值,要求填入1…n∗m,求方案数
n*m≤25~30
BZOJ 2669 局部极小值(PoPoQQQ)
原来只考虑了保证标记的位置都是局部最小值
但是问题是这样虽然保证了标记的位置都是局部最小值,但是可能会导致一些未标记的位置成为局部极小值,因此我们枚举其他可以成为局部极小值的位置,容斥一下即可
所以正解是枚举每一种可能的局部最小值分布,用状压dp求出方案数,然后容斥(一步减,两步加)
对这种先搜索再dp的题的复杂度很不适应: O(Status∗29∗n∗m∗8)
祭奠先bfs后dp的Turn Game
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define inf (1<<30)
#define INF (1ll<<62)
#define fi first
#define se second
#define rep(x,s,t) for(register int x=s,t_=t;x
#define per(x,s,t) for(register int x=t-1,s_=s;x>=s_;--x)
#define travel(x) for(int I=last[x],to;~I&&(to=e[I].to,1);I=e[I].nxt)
#define prt(x) cout<<#x<<":"<
#define prtn(x) cout<<#x<<":"<
#define pb(x) push_back(x)
#define hash asfmaljkg
#define rank asfjhgskjf
#define y1 asggnja
#define y2 slfvm
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
template<class T>void sc(T &x){
int f=1;char c;x=0;
while(c=getchar(),c<48)if(c=='-')f=-1;
do x=x*10+(c^48);
while(c=getchar(),c>47);
x*=f;
}
template<class T>void nt(T x){
if(!x)return;
nt(x/10);
putchar(x%10+'0');
}
template<class T>void pt(T x){
if(x<0)putchar('-'),x=-x;
if(!x)putchar('0');
else nt(x);
}
template<class T>void ptn(T x){
pt(x);putchar('\n');
}
template<class T>void pts(T x){
pt(x);putchar(' ');
}
template<class T>inline void Max(T &x,T y){if(xtemplate <class T>inline void Min(T &x,T y){if(x>y)x=y;}
int n,m,nn;
const int maxn=6;
const int maxm=6;
char ch[maxn][maxn];
const int rx[]={-1,-1,-1,0,0,1,1,1};
const int ry[]={-1,0,1,-1,1,-1,0,1};
const int mod=772002;
const int maxx=9;
ll rem[1<int ay[maxx];
int ax[maxx];
int tot;
ll dp[maxn*maxn][1<//roll?
inline bool free(int x,int y){
rep(k,0,8){
int nx=x+rx[k],ny=y+ry[k];
if(nx<0||nx>=n||ny<0||ny>=m)continue;
if(ch[nx][ny]=='X')
return false;
}
return true;
}
int deal(){
tot=0;
rep(i,0,n)rep(j,0,m)if(ch[i][j]=='X')
ax[tot]=i,ay[tot++]=j;
rep(mask,0,1<0,tot)if(mask>>i&1)ch[ax[i]][ay[i]]='.';
ll &cnt=rem[mask]=0;
rep(i,0,n)rep(j,0,m)
if(ch[i][j]=='.'&&free(i,j))
cnt++;
rep(i,0,tot)if(mask>>i&1)ch[ax[i]][ay[i]]='X';
}
dp[0][0]=1;
rep(i,1,nn+1)rep(mask,0,1<1][mask]*max(rem[mask]-i+1,0ll)%mod;
for(int j=mask;j;j^=j&-j)
(dp[i][mask]+=dp[i-1][mask^(j&-j)])%=mod;
}
return dp[nn][(1<1];
}
ll ans;
void dfs(int x,int y,int cnt){
if(x==n){
// rep(i,0,n)prtn(ch[i]);
(ans+=cnt&1?mod-deal():deal())%=mod;
return;
}
int ny=y==m-1?0:y+1;
int nx=y==m-1?x+1:x;
dfs(nx,ny,cnt);
if(ch[x][y]=='.'&&free(x,y)){
ch[x][y]='X';
dfs(nx,ny,cnt^1);
ch[x][y]='.';
}
}
void solve(){
nn=n*m;
tot=0;
rep(i,0,n)scanf("%s",ch[i]);
rep(i,0,n)rep(j,0,m)
if(ch[i][j]=='X'&&!free(i,j)){
puts("0");
return;
}
ans=0;
dfs(0,0,0);
ptn(ans);
}
int main(){
// freopen("pro.in","r",stdin);
// freopen("chk.out","w",stdout);
int kase=0;
while(~scanf("%d%d",&n,&m)){
printf("Case #%d: ",++kase);
solve();
}
return 0;
}