我不是说了难度要平均值了吗!-SDUT某选拔赛题

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;
}

猜你喜欢

转载自blog.csdn.net/rwbyblake/article/details/103412306