1.空调
思路
1.区间同时加减 1,可以转换成一个差分数组两个端点的操作
2.用 p 减去 t 数组,得到要消除的数组 a,对 a 求差分数组
3.差分数组一正一负为一个操作,因为是把这个原数组区间加上了 1,单独的正负为一个操作
4.总共需要的操作就是差分数组里 max(正数和, 负数和)
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int p[N], t[N], a[N];
int n;
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &p[i]);
for(int i = 1; i <= n; i++){
scanf("%d", &t[i]);
p[i] -= t[i];
}
int pos = 0, neg = 0;
for(int i = 1; i <= n; i++){
a[i] = p[i] - p[i - 1];
if(a[i] > 0) pos += a[i];
else neg -= a[i];
}
printf("%d", max(pos, neg));
return 0;
}
2.差分
思路
模板题
// 模板1
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N], b[N];
int n, m;
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
b[i] = a[i] - a[i - 1];
}
int l, r, c;
while(m--){
scanf("%d%d%d", &l, &r, &c);
b[l] += c;
b[r + 1] -= c;
}
for(int i = 1; i <= n; i++){
a[i] = a[i - 1] + b[i];
printf("%d ", a[i]);
}
return 0;
}
// 模板2
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N];
int n, m;
int insert(int l, int r, int c){
a[l] += c;
a[r + 1] -= c;
}
int main(){
scanf("%d%d", &n, &m);
int x;
for(int i = 1; i <= n; i++){
scanf("%d", &x);
insert(i, i, x);
}
int l, r, c;
while(m--){
scanf("%d%d%d", &l, &r, &c);
insert(l, r, c);
}
for(int i = 1; i <= n; i++){
a[i] += a[i - 1];
printf("%d ", a[i]);
}
return 0;
}
3.差分矩阵
思路
模板题
// 模板1
#include<iostream>
using namespace std;
const int N = 1e3 + 10;
int a[N][N], b[N][N];
int n, m, q;
int main(){
scanf("%d%d%d", &n, &m, &q);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
scanf("%d", &a[i][j]);
b[i][j] = a[i][j] - a[i - 1][j] - a[i][j - 1] + a[i - 1][j - 1];
}
}
int x1, y1, x2, y2, c;
while(q--){
scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &c);
b[x1][y1] += c;
b[x2 + 1][y1] -= c;
b[x1][y2 + 1] -= c;
b[x2 + 1][y2 + 1] += c;
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1] + b[i][j];
printf("%d ", a[i][j]);
}
printf("\n");
}
return 0;
}
// 模板2
#include<iostream>
using namespace std;
const int N = 1e3 + 10;
int a[N][N];
int n, m, q;
int insert(int x1, int y1, int x2, int y2, int c){
a[x1][y1] += c;
a[x2 + 1][y1] -= c;
a[x1][y2 + 1] -= c;
a[x2 + 1][y2 + 1] += c;
}
int main(){
scanf("%d%d%d", &n, &m, &q);
int x;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
scanf("%d", &x);
insert(i, j, i, j, x);
}
}
int x1, y1, x2, y2, c;
while(q--){
scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &c);
insert(x1, y1, x2, y2, c);
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
a[i][j] += a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1];
printf("%d ", a[i][j]);
}
printf("\n");
}
return 0;
}
4.棋盘
思路
取反就是把这个区域都加上 1,每个位置如果和为偶数,那就是没变,和为奇数就是反了
#include<iostream>
using namespace std;
const int N = 2e3 + 10;
int a[N][N], b[N][N];
int n, m;
int main(){
scanf("%d%d", &n, &m);
int x1, y1, x2, y2;
while(m--){
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
b[x1][y1]++;
b[x2 + 1][y1]--;
b[x1][y2 + 1]--;
b[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] + b[i][j]) & 1;
printf("%d", a[i][j]);
}
printf("\n");
}
return 0;
}
5.重新排序
思路
用差分统计每个位置被加了多少次,加的越多的位置选择越大的数
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int a[N], b[N];
int n, m;
long long res1, res2;
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
scanf("%d", &m);
int l, r;
while(m--){
scanf("%d%d", &l, &r);
b[l]++;
b[r + 1]--;
}
for(int i = 1; i <= n; i++) b[i] += b[i - 1];
for(int i = 1; i <= n; i++) res1 += 1ll * a[i] * b[i];
sort(a + 1, a + n + 1);
sort(b + 1, b + n + 1);
for(int i = 1; i <= n; i++) res2 += 1ll * a[i] * b[i];
printf("%lld", res2 - res1);
return 0;
}