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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python方格染色_Luogu P3631 [APIO2011]方格染色

發(fā)布時間:2023/12/19 python 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python方格染色_Luogu P3631 [APIO2011]方格染色 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

思路

對于這道題,我們從題目里可以知道,藍色代表的方塊為0,紅色代表的方塊為1。按照題目要求,如果換一種說法,那就是對于一個2*2的方格,其中1的個數必定有奇數個,這樣的話,每個方格里的所

有數的異或和必定為1(0^0=0 , 1^0=1 , 1^1=0)。那么對于每一個格子\(a(i,j)\),都有:a(i,j)^a(i+1,j)^a(i,j+1)^a(i+1,j+1)=1

我們欽定S(i , j)為每一個以點(i , j)為右下角的方格的異或和。然后把范圍擴大,設想對于一個i*j的方格,它的異或和會是什么呢?(這個部分需要自己推一下,時間關系我就不給例子了)

我們多舉幾個例子,就可以發(fā)現(xiàn)對于任意一個以點(i , j)為右下角的矩陣,它的區(qū)域內所有可能的22的方格的異或和再異或起來,得到的就是以(i , j)為右下角的矩陣中包括的所有22矩陣的異

或和的異或和。而這個異或和,根據a^a=0的規(guī)定,這個矩陣的S(i , j)僅僅與點(1 , 1)、(i , 1)、(1 , j)、(i , j)有關。

再以此類推,我們就可以發(fā)現(xiàn)對于任意一個點,它的值只與(1 , 1)、(i , 1)、(j , 1)這幾個點有關。因此我們就可以知道,只要我們明確了表格中第一列和第一行的內容,那表格中其他點

的內容也就是唯一的。

因此,對于a(1 , 1)^a(i , 1)^(1 , j)^a(i , j),當i,j均為偶數時值為1(此時\((i-1) \times (j-1)\)為奇數,對于S函數的異或前綴和為1),否則為0(此時(i-1)*(j-1)為偶數,對于

S函數的異或前綴和為0)。即為a(1 , 1)^a(i , 1)^(1 , j)^a(i , j)=0/1(這里0/1表示值為0或者1)。

這樣的話,我們可以考慮枚舉a(1 , 1)的值,根據a(i , j)和a(1 , 1)的異同關系(就是對于上一段中說的i , j的奇偶性的問題),就可以確定a(i , 1)和a(1 , j)的異同關系,

即a(i , 1)^a(1 , j)=0/1^0/1^a(i , j)。

那么到現(xiàn)在我們還沒有提到過關于并查集的一個字(而這又是一道并查集的題目)。由于我們可以通過枚舉a(1 , 1)確定出a(i , 1)和a(j , 1)的異同關系,我們就應該有所啟發(fā)。

考慮一下食物鏈那道題。同樣都是維護不同的集合,維護集合的關系,這樣想這兩個題就是極其類似的。我們使用并查集維護有關系的點a(i , 1)和a(j , 1)的異同關系,將他們之間連邊。

最后考慮有多少個集合,答案即為2的集合數量減1次方。有人可能會有疑問,為什么不是2的集合個數次方呢?這是因為(1 , 1)這個點自己就是一個集合,但是對答案并沒有貢獻,所以要減一。

Code

#include

#include

#include

#include

#define MAXN 400005

#define MOD 1000000000

typedef long long ll;

int n, m, k;

int f[MAXN], c[MAXN];//c是指該點與其父節(jié)點的關系,相同或不同

int ans;

struct node{

int r, c, opt;

} inp[MAXN];//存儲讀入的信息

inline int read(void){

int f = 1, x = 0;char ch;

do{ch = getchar();if(ch=='-')f = -1;} while (ch < '0' || ch > '9');

do{ x = x * 10 + ch - '0';ch = getchar();} while (ch >= '0' && ch <= '9');

return f * x;

}

inline int get_father(int x) {

if (f[x] == x) return x;

int f1 = get_father(f[x]);

c[x] = c[x] ^ c[f[x]];//這里不要忘了維護該點與父節(jié)點的關系

return f[x] = f1;

}

inline int quick_pow(int a,int b){

int res = 1;

while(b){

if(b&1)

res = 1ll * res * a % MOD;

a = 1ll * a * a % MOD;

b >>= 1;

}

return res;

}

inline void calc(int flag) {

for (int i = 1; i <= n + m; ++i)

f[i] = i, c[i] = 0;//初始化要到n+m,因為維護的是第一行和第一列的點,共n+m個

if (flag == 1){//如果點(1,1)是1,那么對除該點外所有數處理(詳見題解里推的式子)

for (int i = 1; i <= k; ++i) {

if (inp[i].r > 1 && inp[i].c > 1)

inp[i].opt ^= 1;//0^1=1,1^1=0,0^0=0

}

}

f[n + 1] = 1;//我們把第一列的數從1到m編號,把第一行的點從n+1到n+n編號,那么(1,1)點的編號會有1和n+1兩個,這里直接連邊

for (int i = 1; i <= k; ++i) {//枚舉每一個給定的點

if (inp[i].r == 1 && inp[i].c == 1)

continue;//如果是(1,1),忽略即可

int f1 = get_father(inp[i].r), f2 = get_father(inp[i].c + n);//取父親

if (f1 == f2) {//如果已經在同一集合里了,則判斷是否滿足關系式

if ((c[inp[i].r] ^ c[inp[i].c + n]) != inp[i].opt)

return;//不滿足直接返回

}

else {

f[f1] = f2;//如果不在同一集合,那么連邊

c[f1] = c[inp[i].c + n] ^ c[inp[i].r] ^ inp[i].opt;//更新異同關系

}

}

int cnt = 0;

for (int i = 1; i <= n + m;++i)

if(f[i]==i)++cnt;

ans = (1ll * ans + quick_pow(2, cnt - 1)) % MOD;

}

int main() {

n = read(), m = read();

k = read();

int ck = -1;

for (int i = 1; i <= k; ++i) {

inp[i].r = read(), inp[i].c = read();

inp[i].opt = read();

if ((!(inp[i].r & 1)) && (!(inp[i].c & 1)))

inp[i].opt ^= 1;//如果i,j同是偶數,異或1

if (inp[i].r == 1 && inp[i].c == 1)

ck = inp[i].opt;//若給定了(1,1)的值,存儲下來

}

if (ck == -1 || ck == 0) calc(0);//枚舉

if (ck == -1 || ck == 1) calc(1);

printf("%lld\n", ans);//輸出

return 0;

}

總結

以上是生活随笔為你收集整理的python方格染色_Luogu P3631 [APIO2011]方格染色的全部內容,希望文章能夠幫你解決所遇到的問題。

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