【cf1262E】E. Arson In Berland Forest(二分+二维差分)

传送门

题意:
现有一张\(n\cdot m,n\cdot m\leq 10^6\)的网格图,一开始有些初始火点,之后每一秒火点都会向周围八个格子蔓延。
现已知最终火点分布情况。
要求构造出一个原始火点图,使得经过\(T\)秒后能够到达该终态,并且\(T\)尽可能大。

思路:
显然最后答案具有单调性,那么我们直接二分时间\(T\)
若存在一个格子为火点,那么终态\((2T+1)\cdot (2T+1)\)大小的矩形都会成为火点,根据这一点我们预处理二维前缀和找到所有最后可能成为火点的位置。
之后根据这些位置来\(check\)是否覆盖所有火点即可。
\(check\)时也需要用到二维前缀和。
代码可能写得有点乱:

/*
 * Author:  heyuhhh
 * Created Time:  2020/3/3 15:02:46
 */
#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 = 1e6 + 5;
 
int n, m;
char s[N];
 
bool chk(vector<vector<int>>& res, vector<vector<int>>& mp, vector<vector<ll>>& a, ll T) {
    T = 2 * T + 1;
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < m; j++) {
            res[i][j] = 0;
        }   
    }
    vector <vector <ll>> c(n, vector <ll> (m, 0));
    auto ask = [&] (int r1, int c1, int r2, int c2) {
        ll ans = a[r2][c2];
        if(r1) ans -= a[r1 - 1][c2];
        if(c1) ans -= a[r2][c1 - 1];
        if(r1 && c1) ans += a[r1 - 1][c1 - 1];
        return ans == T * T;
    };
    
    for(int i = 0; i + T - 1 < n; i++) {
        for(int j = 0; j + T - 1 < m; j++) {
            if(ask(i, j, i + T - 1, j + T - 1)) {
                ++c[i][j];
                if(i + T < n) --c[i + T][j];
                if(j + T < m) --c[i][j + T];
                if(i + T < n && j + T < m) ++c[i + T][j + T];
                res[i + T / 2][j + T / 2] = 1;
            }
        }
    }
    for(int i = 0; i < n; i++) {
        for(int j = 1; j < m; j++) {
            c[i][j] += c[i][j - 1];
        }   
    }
    for(int i = 1; i < n; i++) {
        for(int j = 0; j < m; j++) {
            c[i][j] += c[i - 1][j];
        }   
    }
    
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < m; j++) {
            if(mp[i][j] > 0 && c[i][j] <= 0) return false;
        }   
    }
    return true;
}
 
void run() {
    cin >> n >> m;
    vector <vector<int>> a(n, vector<int> (m)), b(n, vector <int> (m)), c(n, vector <int> (m));
    vector <vector <ll>> sum(n, vector <ll> (m));
    for(int i = 0; i < n; i++) {
        cin >> s;
        for(int j = 0; j < m; j++) {
            a[i][j] = (s[j] == 'X' ? 1 : 0);
        }   
    }
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < m; j++) {
            sum[i][j] = a[i][j];
            if(i) sum[i][j] += sum[i - 1][j];
            if(j) sum[i][j] += sum[i][j - 1];
            if(i && j) sum[i][j] -= sum[i - 1][j - 1];
        }   
    }
    int l = 0, r = n * m + 1, mid;
    while(l < r) {
        mid = (l + r) >> 1;
        if(chk(b, a, sum, mid)) {
            l = mid + 1;
            c = b;
        }
        else r = mid;
    }
    cout << l - 1 << '\n';
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < m; j++) {
            if(c[i][j]) cout << 'X';
            else cout << '.';
        }
        cout << '\n';
    }
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}
posted @ 2020-03-09 21:08  heyuhhh  阅读(386)  评论(0编辑  收藏  举报