2020ICPC 小米 网络选拔赛第一场 J.Matrix Subtraction
题目描述
Given a matrix M M_{} M of size n × m n\times m n×m and two integers a , b a, b_{} a,b, determine weither it is possible to make all entrys of M M_{} M zero by repeatedly choosing a × b a\times b a×b submatrices and reduce the values in the chosen matrices by 1. If possible, print “_” in one line, or print “QAQ” in one line.
输入描述:
The first line contains one integer T ( 1 ≤ T ≤ 100 ) T~(1\le T \le 100) T (1≤T≤100), denoting the number of test cases.
For each test case:
The first line contains four integers n , m , a , b ( 1 ≤ n , m ≤ 1000 , 1 ≤ a ≤ n , 1 ≤ b ≤ m ) n,m,a,b~(1\le n,m \le 1000, 1\le a\le n, 1\le b\le m) n,m,a,b (1≤n,m≤1000,1≤a≤n,1≤b≤m), denoting the size of given matrix and the size of chosen submatrices respectively.
The next n n_{} n lines each contains m m_{} m integers M i , j ( 0 ≤ M i , j ≤ 1 0 9 ) M_{i,j}~(0\le M_{i,j} \le 10^9) Mi,j (0≤Mi,j≤109), denoting the entrys of matrix M M_{} M .
It’s guaranteed that ∑ n m ≤ 1 0 6 \sum nm \le 10^6 ∑nm≤106 .
输出描述:
Print T T_{} T lines each containing a string “_” or “QAQ”, denoting the answer to each test case.
示例1
复制
2
2 2 1 2
1 2
1 2
2 3 1 2
1 2 1
1 2 1
输出
QAQ
^_^
二维差分裸题~
试想,对最左上角那个点
a
1
,
1
a_{1,1}
a1,1,显然只能用一个
a
∗
b
a*b
a∗b 的子矩阵操作
a
1
,
1
a_{1,1}
a1,1 次,操作完后发现对点
a
1
,
2
a_{1,2}
a1,2,只需要将子矩阵向右平移一个单位,操作
a
1
,
1
−
a
1
,
2
a_{1,1}-a_{1,2}
a1,1−a1,2 次即可,依次类推,我们只需要按从左到右,从上到下的顺序对所有以
a
x
,
y
a_{x,y}
ax,y 为最左上角的子矩阵操作即可,判断最后是否变成全
0
0
0 矩阵即可。暴力肯定不现实,需要
O
(
n
∗
m
∗
a
∗
b
)
O(n*m*a*b)
O(n∗m∗a∗b),所以要用到二维差分,对每一个块的操作可以优化到
O
(
n
)
O(n)
O(n),AC代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e3+5;
ll a[N][N],diff[N][N];
int n,m,x,y,t;
int main() {
scanf("%d",&t);
while(t--)
{
memset(diff,0,sizeof(diff));
memset(a,0,sizeof(a));
scanf("%d%d%d%d", &n, &m, &x, &y);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
scanf("%lld", &a[i][j]);
diff[i][j] = a[i][j] - a[i - 1][j] - a[i][j - 1] + a[i - 1][j - 1];
}
}
int flag=0;
for (int i = 1; i <= n - x+1; i++) {
for (int j = 1; j <= m - y+1 ; j++) {
ll k= diff[i][j]+ diff[i - 1][j] + diff[i][j - 1] - diff[i - 1][j - 1];
if(k<0){
flag=1;break;
}
diff[i][j]-=k;
diff[i][j+y]+=k;
diff[i+x][j]+=k;
diff[i+x][j+y]-=k;
}
if(flag) break;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
diff[i][j] += diff[i - 1][j] + diff[i][j - 1] - diff[i - 1][j - 1];
if (diff[i][j]) {
flag = 1;
break;
}
}
if(flag) break;
}
if(!flag) printf("^_^\n");
else printf("QAQ\n");
}
return 0;
}