【cf1186E】E. Vus the Cossack and a Field(找规律+递归)

传送门

题意:
给出一个大小为\(n\cdot m\)\(01\)矩形\(A\),记\(A\)矩阵\(0,1\)翻转过后的矩阵为\(A'\)
那么现在执行无限次如下操作:

  • \(A'\)放在\(A\)的右边和下边;
  • \(A\)放在右下角;
  • \(A\)等于新的矩阵,然后回到第一步。

现在给出\(q,q\leq 1000\)次询问,每次询问为\("x_1,y_1,x_2,y_2"\)的形式,要回答这个矩阵区域的和。

思路:
找规律。
首先我们将每个询问转化为求四个前缀和的形式。
将最终的矩阵按照\(n\cdot m\)分块,我们可以找到每个顶点\((x,y)\)所在的块。
前缀中的每一整块都很好计算,答案为\(\frac{nm}{2}\)。并且我们可以发现,对于\(2n\cdot 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 << '\n'; }
  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 << '\n';
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}
posted @ 2020-03-22 22:11  heyuhhh  阅读(251)  评论(0编辑  收藏  举报