[BZOJ2669][CQOI2012]局部最小值(容斥+状压DP)
发现最多有8个限制位置,可以以此为基础DP和容斥。
$f_{i,j}=f_{i-1,j}\times (cnt_j-i+1)+\sum_{k\subset j} f_{i-1,k}$
$cnt_j$表示当限制状态为j时i有多少个可行位置。
这样DP只能保证所有题设位置全部是局部最小值,但不保证其它位置不会变成局部最小值,容斥解决。
$O(DFS*8nm*2^8)$
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 5 using namespace std; 6 7 const int mod=12345678; 8 int dx[9]={0,1,0,-1,0,1,-1,1,-1},dy[9]={0,0,1,0,-1,1,-1,-1,1}; 9 int n,m,ans,l,f[30][1<<8],cnt[1<<8],vis[8][8],a[10][2]; 10 char ch[8][8]; 11 12 int dp(){ 13 memset(f,0,sizeof(f)); 14 memset(cnt,0,sizeof(cnt)); 15 int top=0; 16 rep(i,1,n) rep(j,1,m) if (ch[i][j]=='X') 17 a[++top][0]=i,a[top][1]=j; 18 for (int S=0; S<(1<<top); S++){ 19 memset(vis,0,sizeof(vis)); 20 rep(i,1,top) if (~S&(1<<(i-1))) vis[a[i][0]][a[i][1]]=1; 21 rep(i,1,n) rep(j,1,m){ 22 bool flag=0; 23 rep(l,0,8) if (vis[i+dx[l]][j+dy[l]]) { flag=1; break; } 24 if (!flag) cnt[S]++; 25 } 26 } 27 f[0][0]=1; 28 rep(i,1,n*m) for (int j=0; j<(1<<top); j++){ 29 f[i][j]=(f[i][j]+1ll*f[i-1][j]*max(cnt[j]-i+1,0))%mod; 30 rep(k,1,top) if (j&(1<<(k-1))) 31 f[i][j]=(f[i][j]+f[i-1][j^(1<<(k-1))])%mod; 32 } 33 return f[n*m][(1<<top)-1]; 34 } 35 36 void dfs(int x,int y,int t){ 37 if (y==m+1){ dfs(x+1,1,t); return; } 38 if (x==n+1){ ans=(ans+dp()*(t&1?-1:1))%mod; return; } 39 dfs(x,y+1,t); 40 bool flag=0; 41 rep(i,0,8) if (ch[x+dx[i]][y+dy[i]]=='X') { flag=1; break; } 42 if (!flag) ch[x][y]='X',dfs(x,y+1,t+1),ch[x][y]='.'; 43 } 44 45 int main(){ 46 freopen("bzoj2669.in","r",stdin); 47 freopen("bzoj2669.out","w",stdout); 48 scanf("%d%d",&n,&m); 49 rep(i,1,n) scanf("%s",ch[i]+1); 50 rep(i,1,n) rep(j,1,m) if (ch[i][j]=='X') 51 rep(k,1,8) if (ch[i+dx[k]][j+dy[k]]=='X') { puts("0"); return 0; } 52 dfs(1,1,0); printf("%d\n",(ans+mod)%mod); 53 return 0; 54 }