《算法竞赛进阶指南》0.3前缀与差分
99. 激光炸弹
一种新型的激光炸弹,可以摧毁一个边长为 R的正方形内的所有的目标。
现在地图上有 N个目标,用整数Xi,Yi表示目标在地图上的位置,每个目标都有一个价值Wi。
激光炸弹的投放是通过卫星定位的,但其有一个缺点,就是其爆炸范围,即那个边长为 R
的正方形的边必须和x,y轴平行。
若目标位于爆破正方形的边上,该目标不会被摧毁。
求一颗炸弹最多能炸掉地图上总价值为多少的目标。
输入格式
第一行输入正整数 N和 R,分别代表地图上的目标数目和正方形的边长,数据用空格隔开。
接下来N行,每行输入一组数据,每组数据包括三个整数Xi,Yi,Wi,分别代表目标的x坐标,y坐标和价值,数据用空格隔开。
输出格式
输出一个正整数,代表一颗炸弹最多能炸掉地图上目标的总价值数目。
数据范围
0<N≤10000,
0≤Xi,Yi≤5000
输入样例:
2 1
0 0 1
1 1 1
输出样例:
1
#include <iostream>
using namespace std;
const int N = 5010;
int g[N][N];
int main()
{
int N, R;
cin >> N >> R;
int n = R, m = R; //判断边界
for(int i = 0, x, y, w; i < N; i++)
{
cin >> x >> y >> w;
x++, y++;
n = max(n, x), m = max(m, y);
g[x][y] += w;
}
//求前缀和
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
g[i][j] += g[i - 1][j] + g[i][j - 1] - g[i - 1][j - 1];//加了两次,减一次
int res = 0;
for(int i = R; i <= n; i++)
for(int j = R; j <= m; j++)
res = max(res, g[i][j] - g[i - R][j] - g[i][j - R] + g[i - R][j - R]);
cout << res << endl;
return 0;
}
100. IncDec序列
给定一个长度为 n 的数列 a1,a2,…,an,每次可以选择一个区间 [l,r],使下标在这个区间内的数都加一或者都减一。
求至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列可能有多少种。
输入格式
第一行输入正整数n。
接下来n行,每行输入一个整数,第i+1行的整数代表ai。
输出格式
第一行输出最少操作次数。
第二行输出最终能得到多少种结果。
数据范围
0<n≤105,
0≤ai<2147483648
输入样例:
4
1
1
2
2
输出样例:
1
2
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010;
int a[N];
int main()
{
int n;
cin >> n;
for(int i = 1; i <=n; i++) cin >> a[i];
for(int i = n; i > 1; i--) a[i] -= a[i - 1];
LL pos = 0, neg = 0; // 差分序列中正数之和pos,负数之和neg
for(int i = 2; i <= n; i++)
if(a[i] > 0) pos += a[i];
else neg -= a[i];
cout << min(pos, neg) + abs(pos - neg) << endl;
cout << abs(pos - neg) + 1;
}
101. 最高的牛
有 N头牛站成一行,被编队为1、2、3…N,每头牛的身高都为整数。
当且仅当两头牛中间的牛身高都比它们矮时,两头牛方可看到对方。
现在,我们只知道其中最高的牛是第 P头,它的身高是 H,剩余牛的身高未知。
但是,我们还知道这群牛之中存在着 M对关系,每对关系都指明了某两头牛 A 和 B可以相互看见。
求每头牛的身高的最大可能值是多少。
输入格式
第一行输入整数N,P,H,M,数据用空格隔开。
接下来M行,每行输出两个整数 A和 B ,代表牛 A 和牛 B可以相互看见,数据用空格隔开。
输出格式
一共输出 N行数据,每行输出一个整数。
第 i行输出的整数代表第 i头牛可能的最大身高。
数据范围
1≤N≤10000,
1≤H≤1000000,
1≤A,B≤10000,
0≤M≤10000
输入样例:
9 3 5 5
1 3
5 3
4 3
3 7
9 8
输出样例:
5
4
5
3
4
4
5
5
5
注意:此题中给出的关系对可能存在重复
#include <iostream>
#include <set>
using namespace std;
const int N = 10010;
int height[N];
int main()
{
int n, p, h, m;
cin >> n >> p >> h >> m;
height[1] = h;
set<pair<int, int>> existed;
for(int i = 0, a, b; i < m; i++)
{
cin >> a >> b;
if(a > b) swap(a, b);
if(!existed.count({a, b})) //a,b
{
existed.insert({a, b});
height[a + 1] --, height[b] ++;
}
}
for(int i = 1; i <=n; i++)
{
height[i] += height[i - 1];
cout << height[i] << endl;
}
return 0;
}