题目链接:哆啦A梦传送门
题意:给出原始n行m列矩阵A,他的反置矩阵为B(与A相对应的位置取反)。
原始矩阵 : A
第一次可以变成:
[
A
B
B
A
]
\begin{bmatrix} A&B \\ B& A \end{bmatrix}
[ABBA]
以此类推。
现在有q个询问,每次询问左上角为(x1,y1),右下角为(x2,y2)的矩阵的总和。
我们可以发现N行M列的矩阵A+B=N*M,这个很容易可以得到。
再者,我们观察题目给的数据:
[
1
0
0
1
0
1
1
0
1
1
0
0
0
0
1
1
0
1
1
0
1
0
0
1
0
0
1
1
1
1
0
0
0
1
1
0
1
0
0
1
0
0
1
1
1
1
0
0
1
0
0
1
0
1
1
0
1
1
0
0
0
0
1
1
]
\begin{bmatrix} 1&0 &0 &1 &0 &1 &1 &0 \\ 1& 1& 0 &0 &0 &0 &1 &1 \\ 0&1 &1 &0 &1 &0 &0 &1 \\ 0& 0&1 &1 &1 &1 &0 &0 \\ 0&1 &1 &0 &1 &0 &0 &1 \\ 0&0 &1 &1 &1 &1 &0 &0 \\ 1&0 &0 &1 &0 &1 &1 &0 \\ 1&1 &0 &0 &0 &0 &1 &1 \end{bmatrix}
⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡1100001101101001001111001001011000111100100101101100001101101001⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤
可以发现:相邻的奇数行与偶数行,技术列与偶数列对应的点值异或为1。
那么我们就可以解决了。
我们设
f
(
x
,
y
)
f(x,y)
f(x,y)表示为左上角为(1,1),右下角为(x,y)的矩阵和。
那么此题要求的结果就为:
s
u
m
=
f
(
x
2
,
y
2
)
−
f
(
x
1
−
1
,
y
2
)
−
f
(
x
2
−
1
,
y
1
)
+
f
(
x
1
,
y
1
)
sum=f(x2,y2)-f(x1-1,y2)-f(x2-1,y1)+f(x1,y1)
sum=f(x2,y2)−f(x1−1,y2)−f(x2−1,y1)+f(x1,y1)
这是我们先让原始矩阵变换为下一个矩阵,就变为2n2m的矩阵了(n<<=1,m<<=1)。
此时对于求
f
(
x
,
y
)
f(x,y)
f(x,y),因为我们已经知道nm的矩阵值,故我们可以看看在范围为(1,1)->(x,y)中有多少个为n*m的矩阵块,这些值都是固定的,那么此时还剩下a=x%n,b=y%m,也就是a行m列,n行b列以及a行b列。
根据我们前面说的发现,a行m列,n行b列的值其实也固定了(就为一半),为什么呢?
我们可以知道总点(1,1)到(a,m)以及(n,b)如果c与d不全为奇数,那么此时这个(c,d)矩阵和就为
c
∗
d
2
\frac{c*d}{2}
2c∗d,这肯定是显然的,因为一开始我们就变换了一次矩阵,是的边长都扩大为2倍,即n,m都为偶数。即现在的结果为
x
∗
y
−
a
∗
b
2
\frac{x*y-a*b}{2}
2x∗y−a∗b(没算(a,b))。
那么现在就剩下a行b列没求了,此时我们可以预处理出n行m列的
f
(
x
,
y
)
∣
x
<
=
n
,
y
<
=
m
f(x,y)|x<=n,y<=m
f(x,y)∣x<=n,y<=m。
但我们还需要知道此时a行b列的矩阵是否是取反的矩阵,
这里有个技巧:
记
b
i
t
c
n
t
(
x
)
bitcnt(x)
bitcnt(x)为x的二进制表示下1的数量,若bitcnt(x/n)+bitcnt(y/m)为奇数,则(x,y)处于矩阵B中,否则(x,y)处于矩阵A中。
证明:
假设处于矩阵A,那么直接加上预处理的结果,否则a*b-预处理的结果。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long LL;
const int N=1010;
int num[N][N];
int n,m;
int q;
LL solve(LL x,LL y)
{
if(x<=0||y<=0) return 0;
LL a=x%n,b=y%m;
LL sum=(x*y-a*b)/2;
if(((__builtin_popcountll(x/n))^(__builtin_popcountll(y/m)))&1){
sum=sum+(a*b-num[a][b]);
}
else sum+=num[a][b];
return sum;
}
int main()
{
cin>>n>>m>>q;
for(int i=1;i<=n;i++)
{
string s;
cin>>s;
for(int j=1;j<=m;j++){
int x=s[j-1]-'0';
num[i][j]=num[i+n][j+m]=x;
num[i+n][j]=num[i][j+m]=x^1;
}
}
n<<=1;
m<<=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++){
num[i][j]+=(num[i-1][j]+num[i][j-1]-num[i-1][j-1]);
}
}
while(q--)
{
LL x1,y1,x2,y2;
scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
printf("%lld\n",solve(x2,y2)-solve(x1-1,y2)-solve(x2,y1-1)+solve(x1-1,y1-1));
}
return 0;
}