Problem Description
“給出一個 n * m 大小的矩形 , 然後每次給次 x1 , y1 , x2 , y2 四個數。”
“那個…等等麥露!是不是有什麼不太對的對方?w(゚Д゚)w” “嗯?應該沒有吧。”
“我們是hunter吧,我們應該是hunter的吧,爲什麼我們4人要在這裏做這些奇怪的問題呀!”
“沒關係的,這題很普通,話說這不是烈娜接下的委託嗎。” “雖然是這樣的…不過這明顯不在我的知識範圍內了呀,說什麼要求以 ( x1 , y1
) 爲左上角和 ( x2 , y2 ) 爲右下角矩陣內數的異或和,異或是個是什麼東西,加減就已經是我的極限了啊!”
“emmm…異或就是異或了,那個XOR呀,^呀,二進制運算之類的” “說的再清楚一點呀!” “比如…比如…
那個來代表異或運算,00=0 , 0^1=1 , 1^0=1 , 1^1=0 ,
題面上也說了矩陣裏只有0和1了,這樣就可以做了吧,大概”
Input
第一行輸入兩個數n,m表示矩陣的大小(0<n<=2e3,0<m<=2e3) 接下來的n行每行有m個整數,表示每個位置的數a(0<=a<=1)
接下來一行輸入一個q(0<q<=1e5),代表q次詢問 每次給出x1 y1 x2 y2(0<x1<=x2<=n,0<y1<=y2<=m)
Output
輸出有q行,對應每一次詢問的答案.
Sample Input
2 2 0 1 0 1 1 1 1 1 1
這道題要說難其實真不難,只要搞懂了多個數據異或和的運算剩下的就好辦了
多個數據的異或和相當於這些數據的和對2取餘,例如1,1,1的異或和是3%2 = 1
1,0,1,0的異或和是2%2 = 0
搞懂這些之後,我們只需要將範圍內的數值和運算一下即可。但是如果我們一個一個相加的話,會導致超時,所以這裏需要使用一個小技巧(鬼知道大佬們都多早就知道這個小技巧了…)
例如我們如果要求
1 1 0
0 1 0
1 0 1
這個矩陣從左上角到右下角的數值和,那麼我們可以先把這個矩陣從左加到右,變成下面這個樣子
1 2 2
0 1 1
1 1 2
再將得到的矩陣豎着從上加到下
1 2 2
1 3 3
2 4 5
那麼我們對得到的這個矩陣做一下簡單的四則運算,就可以得到我們想要的範圍內的值了
比如我們想要原矩陣(2,2)-(3,3)的值,我們只需要用(3,3)-(3,3-2)-(3-2,3)+(2-1,2-1)這個算式便可以算出原矩陣(2,2)-(3,3)的值了
比如這裏就是5-2-2+1=2
下面放出我的ac代碼
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
int n,m,q,x1,x2,y1,y2,sum;
int b;
cin>>n>>m;
int a[2005][2005]; //橫着相加的儲存數組
int c[2005][2005]; //豎着相加的儲存數組
memset(a,0,sizeof(a));
memset(c,0,sizeof(c));
for(int i = 1;i<=n;i++)
for(int j = 1;j<=m;j++){
scanf("%d",&b);
a[i][j] = a[i][j-1]+b; //輸入並橫着相加
}
for(int i = 1;i<=n;i++)
for(int j = 1;j<=m;j++)
c[i][j] = c[i-1][j]+a[i][j]; //豎着相加
cin>>q;
while(q--)
{
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
sum =c[x2][y2]-c[x2][y1-1]-c[x1-1][y2]+c[x1-1][y1-1];
cout<<sum%2<<endl;
}
return 0;
}