【BZOJ2669】【JZOJ4700】Garden

    xiaoxiao2026-09-17  0

    Description

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

    Data Constraint

    Solution

    对于20%的数据直接暴力即可。

    对于另30%的数据,可以发现局部极小值最多只有8个,可以用状压dp。

    对于一个合法的数填写方案,其中的数放置的顺序对其是没有影响的,所以我们把数从小到大填进去。我们用 Fi,S 表示当前填到第 i 个数,“X”被填的状态是S。那么有以下两种情况。

    如果我们填的是一个非“X”的格子,我们记没有被填的“X”和它周围的格子的个数是tot,那么这tot个格子都不能填(因为我们填入的是一个非“X”的格子,而且格子周围的数要比格子大,那么我们从小到大填的话必须先填“X”)。那么能填入的位置就有 nmtoti+1 个。我们预处理出一个数组 RestS 记录 S 这个状态的nmtot

    如果我们填的是“X”的格子呢?那么我们可以从没有填这个“X”的状态转移过来。

    于是转移方程就可以得出:

    Fi,S=Fi1,S(RestSi+1)+jSFi1,Sj

    那么就可以过30%的数据了。

    对于100%的数据,如果直接用上面的转移,那么一些被“.”包围的“.”被填入的数小于周围的数的方案数会被统计进答案,所以我们需要用 dfs 找出所有被“.”包围的“.”,然后强制把这个位置改成“X”,计算方案数,然后再容斥一下即可。

    Code

    #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #define fo(i,j,k) for(int i=j;i<=k;i++) #define fd(i,j,k) for(int i=j;i>=k;i--) #define N 11 #define ll long long #define M 1100 #define mo 12345678 using namespace std; int n,m; char ss[N]; int map[N][N]; int rest[M]; int p=0; ll f[N*N][M]; int fx[8][2]={{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}}; struct node{ int x,y; }b[N],z[M]; bool bz[N][N]; int cnt; ll find() { p=0; fo(i,1,n) fo(j,1,m) if(map[i][j]) { p++; b[p].x=i; b[p].y=j; } fo(s,0,(1<<p)-1) { memset(bz,0,sizeof(bz)); fo(i,1,p) if(!((1<<i-1)&s)) { bz[b[i].x][b[i].y]=true; fo(j,0,7) { int x=b[i].x+fx[j][0],y=b[i].y+fx[j][1]; if(x<1 || x>n || y<1 || y>m) continue; bz[x][y]=true; } } int tot=0; fo(i,1,n) fo(j,1,m) if(bz[i][j]) tot++; rest[s]=n*m-tot; } memset(f,0,sizeof(f)); f[0][0]=1; fo(i,1,n*m) fo(s,0,(1<<p)-1) { f[i][s]=f[i-1][s]*(rest[s]-i+1)%mo; fo(j,1,p) if(s&(1<<j-1)) f[i][s]=(f[i][s]+f[i-1][s-(1<<j-1)])%mo; } return f[n*m][(1<<p)-1]%mo; } ll ans=0; void dfs(int dep,int t) { if(dep>cnt) { ll tmp=find(); if(t%2) ans=(ans-tmp+mo)%mo; else ans=(ans+tmp)%mo; return; } dfs(cnt+1,t); fo(k,dep,cnt) { bool tf=true; fo(i,0,7) { int x=z[k].x+fx[i][0],y=z[k].y+fx[i][1]; if(x<1 || x>n || y<1 || y>m) continue; if(map[x][y]) { tf=false; break; } } if(tf) { map[z[k].x][z[k].y]=1; dfs(k+1,t+1); map[z[k].x][z[k].y]=0; } } } bool check() { bool tf=true; int X=0; fo(i,1,n) { fo(j,1,m) if(map[i][j]) { X++; fo(k,0,7) { int x=i+fx[k][0],y=j+fx[k][1]; if(x<1 || x>n || y<1 || y>m) continue; if(map[x][y]) { tf=false; break; } } if(!tf) break; } if(!tf) break; } if(!X) tf=false; return tf; } int main() { int T; cin>>T; while(T--) { scanf("%d %d",&n,&m); p=0; fo(i,1,n) { scanf("%s",ss+1); fo(j,1,m) map[i][j]=(ss[j]=='X'); } if(!check()) { printf("0\n"); continue; } cnt=0; fo(i,1,n) fo(j,1,m) if(!map[i][j]) { bool tf=true; fo(k,0,7) { int x=i+fx[k][0],y=j+fx[k][1]; if(x<1 || x>n || y<1 || y>m) continue; if(map[x][y]) { tf=false; break; } } if(tf) { cnt++; z[cnt].x=i; z[cnt].y=j; } } ans=0; dfs(1,0); printf("%lld\n",ans); } }

    参考资料

    http://wenku.baidu.com/view/f11077fc770bf78a6529543e.html

    转载请注明原文地址: https://ju.6miu.com/read-1312114.html
    最新回复(0)