题解:P13787 地毯 加强版
weichenglu · · 题解
题目描述
在
思路分析
方法一(TLE)
最简单的方法即为暴力。使用二维数组
#include <bits/stdc++.h>
#define N 5005
#define int long long
using namespace std;
int n,m;
int a[N][N];
int sum;
signed main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> n >> m;
for (int i=1;i<=m;++i){
int x1,y1,x2,y2; cin >> x1 >> y1 >> x2 >> y2;
for (int x=x1;x<=x2;++x){
for (int y=y1;y<=y2;++y){
a[x][y]++;
}
}
}
for (int i=1;i<=n;++i){
for (int j=1;j<=n;++j){
sum += (i + j) ^ a[i][j];
}
}
cout << sum;
return 0;
}
这样实现的时间复杂度为
方法二(50 Pts)
我们考虑减少读入地毯时的一层循环,由于涉及到区间求和,我们可以考虑使用差分。
可以将地图看成
假设一个一维数组
- 对于所有
1 \le i \le n ,预处理出d_i \gets d_i - d_{i-1} 。(由于本题初始数组元素都为0 ,所以无需进行此操作) - 读入
l 与r ,修改此区间的两个端点的值,使d_l 加1 ,d_{r+1} 减1 。 - 每行从左往右扫描一遍,跑一遍一维前缀和,即使
d_i \gets d_i + d_{i-1} ,就可以得到每个格子的地毯覆盖数。
代码如下:
#include <bits/stdc++.h>
#define N 5005
#define int long long
using namespace std;
int n,m;
int a[N][N];
int sum;
signed main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> n >> m;
for (int i=1;i<=m;++i){
int x1,y1,x2,y2; cin >> x1 >> y1 >> x2 >> y2;
for (int j=x1;j<=x2;++j) a[j][y1]++,a[j][y2+1]--;
}
for (int i=1;i<=n;++i){
for (int j=1;j<=n;++j){
a[i][j] += a[i][j-1];
sum += (i + j) ^ a[i][j];
}
}
cout << sum;
return 0;
}
但是,这样实现的时间复杂度为
方法三(100 Pts)
由于此题
假设一个二维数组
- 对于所有
1 \le i \le n 与1 \le j \le n ,预处理出d_{i,j} \gets d_{i,j} - d_{i-1,j} - d_{i,j-1} + d_{i-1,j-1} 。(由于本题初始数组元素都为0 ,所以无需进行此操作) - 读入
x1 、y1 、x2 与y2 ,修改此矩形的四个端点的值,使d_{x1,y1} 加1 ,d_{x1,y2+1} 减1 ,d_{x2+1,y1} 减1 ,d_{x2+1,y2+1} 加1 。 - 从上到下、从左往右扫描一遍,跑一遍二维前缀和,即使
d_{i,j} \gets d_{i,j} + d_{i-1,j} + d_{i,j-1} - d_{i-1,j-1} ,就可以得到每个格子的地毯覆盖数。
代码如下:
#include <bits/stdc++.h>
#define N 5005
#define int long long
using namespace std;
int n,m;
int a[N][N];
int sum;
signed main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> n >> m;
for (int i=1;i<=m;++i){
int x1,y1,x2,y2; cin >> x1 >> y1 >> x2 >> y2;
a[x1][y1]++;
a[x1][y2+1]--;
a[x2+1][y1]--;
a[x2+1][y2+1]++;
}
for (int i=1;i<=n;++i){
for (int j=1;j<=n;++j){
a[i][j] += a[i-1][j] + a[i][j-1] - a[i-1][j-1];
sum += (i + j) ^ a[i][j];
}
}
cout << sum;
return 0;
}
此代码的时间复杂度为
注意
不开 long long 见祖宗