题意:
给出一个大小为(ncdot m)的(01)矩形(A),记(A)矩阵(0,1)翻转过后的矩阵为(A')。
那么现在执行无限次如下操作:
- 将(A')放在(A)的右边和下边;
- 将(A)放在右下角;
- 令(A)等于新的矩阵,然后回到第一步。
现在给出(q,qleq 1000)次询问,每次询问为("x_1,y_1,x_2,y_2")的形式,要回答这个矩阵区域的和。
思路:
找规律。
首先我们将每个询问转化为求四个前缀和的形式。
将最终的矩阵按照(ncdot m)分块,我们可以找到每个顶点((x,y))所在的块。
前缀中的每一整块都很好计算,答案为(frac{nm}{2})。并且我们可以发现,对于(2ncdot 2m)矩阵的每一行、每一列,(1)的个数都为元素个数的一半。
那么根据这一点,我们可以直接根据(x,y)的奇偶性分类讨论计算答案。
对于((x,y))所在格子,我们还需要知道这个格子是否翻转,随便写个递归求解就行。
十分十分乱的代码如下:
/*
* Author: heyuhhh
* Created Time: 2020/3/17 16:35:58
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '
'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1000 + 5;
int n, m, q;
char s[N][N];
int mp[N][N];
int sum[N][N];
int find_bel(int r, int c, int x, int y) {
if(x <= r / 2) {
if(y <= c / 2) return 0;
return 1;
} else {
if(y <= c / 2) return 2;
return 3;
}
}
int find(int x, int y, int v) {
int r = 1, c = 1;
if(x == r && y == c) return v;
while(r < x || c < y) r <<= 1, c <<= 1;
int t = find_bel(r, c, x, y);
if(t == 0) return v;
if(t == 1) {
y -= c / 2;
return find(x, y, v ^ 1);
}
if(t == 2) {
x -= r / 2;
return find(x, y, v ^ 1);
}
if(t == 3) {
x -= r / 2, y -= c / 2;
return find(x, y, v);
}
}
pii find_blo(int x, int y) {
return MP((x + n - 1) / n, (y + m - 1) / m);
}
void run() {
cin >> n >> m >> q;
for(int i = 1; i <= n; i++) {
cin >> (s[i] + 1);
for(int j = 1; j <= m; j++) {
mp[i][j] = (s[i][j] == '1');
sum[i][j] = mp[i][j];
}
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
sum[i][j] += sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
}
}
auto solve = [&] (int x, int y) {
if(x < 1 || y < 1) return 0ll;
pii block = find_blo(x, y);
int r = x - n * (block.fi - 1), c = y - m * (block.se - 1);
int t = find(block.fi, block.se, 0);
ll res = 0;
if(block.fi & 1) {
if(block.se & 1) {
res += 1ll * (block.fi - 1) * (block.se - 1) / 2 * n * m;
res += 1ll * (block.se - 1) / 2 * r * m;
res += 1ll * (block.fi - 1) / 2 * c * n;
if(!t) res += sum[r][c];
else res += r * c - sum[r][c];
} else {
res += 1ll * (block.fi - 1) * (block.se - 1) / 2 * n * m;
res += 1ll * (block.fi - 1) / 2 * n * c;
res += 1ll * (block.se - 2) / 2 * r * m;
if(!t) res += sum[r][c];
else res += r * c - sum[r][c];
int t1 = find(block.fi, block.se - 1, 0);
if(!t1) res += sum[r][m];
else res += r * m - sum[r][m];
}
} else {
if(block.se & 1) {
res += 1ll * (block.fi - 1) * (block.se - 1) / 2 * n * m;
res += 1ll * (block.fi - 2) / 2 * n * c;
res += 1ll * (block.se - 1) / 2 * r * m;
if(!t) res += sum[r][c];
else res += r * c - sum[r][c];
int t1 = find(block.fi - 1, block.se, 0);
if(!t1) res += sum[n][c];
else res += n * c - sum[n][c];
} else {
res += 1ll * (block.fi - 2) * (block.se - 2) / 2 * n * m;
res += 1ll * (block.fi - 2) / 2 * n * (m + c);
res += 1ll * (block.se - 2) / 2 * m * (n + r);
int t1 = find(block.fi - 1, block.se - 1, 0);
if(!t1) res += sum[n][m];
else res += n * m - sum[n][m];
t1 = find(block.fi - 1, block.se, 0);
if(!t1) res += sum[n][c];
else res += n * c - sum[n][c];
t1 = find(block.fi, block.se - 1, 0);
if(!t1) res += sum[r][m];
else res += r * m - sum[r][m];
if(!t) res += sum[r][c];
else res += r * c - sum[r][c];
}
}
return res;
};
while(q--) {
int r1, c1, r2, c2;
cin >> r1 >> c1 >> r2 >> c2;
ll ans = solve(r2, c2) - solve(r1 - 1, c2) - solve(r2, c1 - 1) + solve(r1 - 1, c1 - 1);
cout << ans << '
';
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
run();
return 0;
}