日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【BZOJ-2669】局部极小值 状压DP + 容斥原理

發(fā)布時間:2025/7/14 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【BZOJ-2669】局部极小值 状压DP + 容斥原理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

2669: [cqoi2012]局部極小值

Time Limit:?3 Sec??Memory Limit:?128 MB
Submit:?561??Solved:?293
[Submit][Status][Discuss]

Description

有一個n行m列的整數(shù)矩陣,其中1到nm之間的每個整數(shù)恰好出現(xiàn)一次。如果一個格子比所有相鄰格子(相鄰是指有公共邊或公共頂點)都小,我們說這個格子是局部極小值。 給出所有局部極小值的位置,你的任務是判斷有多少個可能的矩陣。

Input

輸入第一行包含兩個整數(shù)n和m(1<=n<=4, 1<=m<=7),即行數(shù)和列數(shù)。以下n行每行m個字符,其中“X”表示局部極小值,“.”表示非局部極小值。

Output

輸出僅一行,為可能的矩陣總數(shù)除以12345678的余數(shù)。

Sample Input

3 2
X.
..
.X

Sample Output

60

HINT

Source

Solution

這道題有點勁!自己沒想出來,于是看的論文 ?傳送門? ?下面引用論文里的題解

對于一個合法的數(shù)填寫方案,其中的數(shù)放置的順序對其是沒有影響的,于是我們可以從1開始填數(shù),并且一個一個地填進格子。如果采取這樣的做法,那么所有的“X”必然要在其周邊所有的格子填數(shù)之前就填好一個數(shù),而"X"有多少呢?很顯然最多只有8個而已。這時我們就可以想到這樣的一個狀態(tài)壓縮方式:opt[i][j](j是一個二進制表達)表示的是i及其以后的數(shù)還沒有填進格子,被填寫了數(shù)的“X”集合狀態(tài)為j的情況下的方案數(shù)。

如上圖4*7的矩陣中,紅色的"X"表示已經(jīng)填寫數(shù)的"X",紅色的格子表示已經(jīng)填寫數(shù)的非"X"格子,那么可以表述成這樣的狀態(tài)opt[8][num](8表示已經(jīng)填寫了7個數(shù),下一個填寫8,num是011010的表示,含義是第2、3、5個"X"已經(jīng)填寫了數(shù)了)

如果我們轉移的話就會有兩種情況:

第一種情況就是把i填進一個"X"中,這個顯然只要枚舉一下放哪一個"X",然后把這個"X"加入j表示的集合里就可以了。

?

如上圖,下一步我們填寫"X"是可以隨意的,因為只要存在解,任意的"X"都是互不影響的。當前的狀態(tài)為f[8][num1](num1為011010的表示),可以推導到f[9][num2](num2為111010、011110、011011的表示)。

第二種情況就是把i填進一個非"X"中,這樣的選擇就有很多了。對于全圖我們一共有n*m個格子,若沒有填進去數(shù)的"X"格子以及其周邊的格子共有tot個,顯然這tot個格子都是不能填i的(因為填進的是一個非"X",并且一個沒有填進去數(shù)的"X"格子其周邊因為都要比它小,所以這兩者都不可以填i),又因為已經(jīng)填寫了1到i-1所有的數(shù),所以剩下能填的選擇數(shù)就是n*m-tot-(i-1)。

?

如上圖,所有的藍色區(qū)域都是無法填寫i的,而下一步能填寫的格子就只有白色的格子,即4*7-17-7=4個格子。

由于這樣的處理方式,尤其是第二種轉移可能會導致非"X"點變?yōu)樽钚≈?#xff0c;所以還需要使用容斥原理來解決。

Code

#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; #define LL long long #define P 12345678 int N,M,ANS,bin[11],f[100][256],cnt[256]; char mp[10][10]; int dx[10]={-1,-1,-1,0,0,0,1,1,1,0},dy[10]={-1,0,1,-1,0,1,-1,0,1,0}; inline bool OK(int x,int y) {return x>=1 && x<=N && y>=1 && y<=M;} #define Pa pair<int,int> Pa stack[100]; int top; bool visit[10][10]; inline void PreWork() {top=0;for (int i=1; i<=N; i++)for (int j=1; j<=M; j++)if (mp[i][j]=='X') stack[top++]=make_pair(i,j);for (int i=0; i<bin[top]; i++){cnt[i]=0; memset(visit,0,sizeof(visit));for (int j=0; j<top; j++) if (~i&bin[j]) visit[stack[j].first][stack[j].second]=1;for (int j=1; j<=N; j++)for (int k=1; k<=M; k++)if (!visit[j][k]){bool flag=1;for (int d=0,x,y; d<=8 && flag; d++) x=j+dx[d],y=k+dy[d],flag=!visit[x][y];cnt[i]+=flag;}} } inline int DP() {PreWork();memset(f,0,sizeof(f));f[0][0]=1;for (int i=1; i<=N*M; i++)for (int j=0; j<bin[top]; j++){for (int k=0; k<top; k++)if (j&bin[k]) (f[i][j]+=f[i-1][j^bin[k]])%=P;(f[i][j]+=(LL)f[i-1][j]*(cnt[j]-(i-1))%P)%=P;}return f[N*M][bin[top]-1]; } inline void DFS(int dep,int x,int y) {if (y==M+1) {DFS(dep,x+1,1); return;}if (x==N+1) {(ANS+=(LL)DP()*(dep&1? -1:1)%P)%=P; return;}DFS(dep,x,y+1);bool flag=1;for (int i=0; i<=8 && flag; i++)if (mp[x+dx[i]][y+dy[i]]=='X') flag=0;if (flag) mp[x][y]='X',DFS(dep+1,x,y+1),mp[x][y]='.'; } int main() {bin[0]=1; for (int i=1; i<=10; i++) bin[i]=bin[i-1]<<1;scanf("%d%d",&N,&M);for (int i=1; i<=N; i++) scanf("%s",mp[i]+1);DFS(0,1,1);printf("%d\n",(ANS+P)%P);return 0; }

菜雞.jpg

轉載于:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5957956.html

總結

以上是生活随笔為你收集整理的【BZOJ-2669】局部极小值 状压DP + 容斥原理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。