【枚举+差分】P6070 『MdOI R1』Decrease
题目
P6070 『MdOI R1』Decrease
分析
刚拿到这道题的时候很明显就看出来要做差分,而且将矩阵中所有的数变成0大概率是要暴力枚举,再结合数据范围 n 只有 5e3,可以确定是暴力枚举+差分了。
但是如何枚举呢?想了半天也感觉无从下手。这是因为本题的关键点没有理解,本题考察了原数组跟差分数组的联系,原数组全部为0的时候,其对应的差分数组的值也全部为0。那么这样就可以从枚举 k x k 矩阵的所有点挨个修改值优化成只枚举 k x k 的左上端点,然后使用insert修改矩阵的值。时间复杂度由O(n∗k2)O(n*k^2)O(n∗k2)优化成了O(n)O(n)O(n)。
代码
#include<iostream>using namespace std;typedef long long LL;const int N = 5e3 + 10;int n,m,k;//只需要差分数组
LL f[N][N]; void insert(int x1, int y1, int x2, int y2, int z)
{f[x1][y1] += z;f[x1][y2 + 1] -= z;f[x2 + 1][y1] -= z;f[x2 + 1][y2 + 1] += z;
}int main()
{cin >> n >> m >> k;while(m--){int x,y,z; cin >> x >> y >> z;insert(x, y, x, y, z);}LL sum = 0; //总操作次数可能超过int范围for(int i=1;i<=n-k+1;i++){for(int j=1;j<=n-k+1;j++){sum += abs(f[i][j]);insert(i, j, i + k - 1, j + k - 1, -f[i][j]); //-f[i][j]为了抵消原f[i][j],使其值变为0 }}//检查n x n范围内的差分数组的值有没有不为0的,如果有就代表无法完成 for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(f[i][j]){cout << -1 << endl;return 0;}cout << sum << endl;return 0;
}