前缀和数组:
S[i] =
∑
j
=
1
i
A
[
j
]
\displaystyle\sum_{j=1}^{i} A[j]
j=1∑iA[j]
sum(l.r)=
∑
i
=
l
r
A
[
i
]
\displaystyle\sum_{i=l}^{r} A[i]
i=l∑rA[i]=S[r]-s[l-1]
例题:
地图上有 N 个目标,用整数 Xi,Yi 表示目标在地图上的位置,每个目标都有一个价值 Wi。
注意:不同目标可能在同一位置。
现在有一种新型的激光炸弹,可以摧毁一个包含 R×R 个位置的正方形内的所有目标。
激光炸弹的投放是通过卫星定位的,但其有一个缺点,就是其爆炸范围,即那个正方形的边必须和 x,y 轴平行。
求一颗炸弹最多能炸掉地图上总价值为多少的目标。
输入格式
第一行输入正整数 N 和 R,分别代表地图上的目标数目和正方形的边长,数据用空格隔开。
接下来 N 行,每行输入一组数据,每组数据包括三个整数 Xi,Yi,Wi,分别代表目标的 x 坐标,y 坐标和价值,数据用空格隔开。
输出格式
输出一个正整数,代表一颗炸弹最多能炸掉地图上目标的总价值数目。
数据范围
0≤R≤109
0<N≤10000,
0≤Xi,Yi≤5000
0≤Wi≤1000
输入样例:
2 1
0 0 1
1 1 1
输出样例:
1
ACWING99
题解:
因为S[i,j]=
∑
x
=
1
i
∑
y
=
1
j
A
[
x
,
y
]
\displaystyle\sum_{x=1}^{i}\sum_{y=1}^{j} A[x,y]
x=1∑iy=1∑jA[x,y]
所以S[i,j]=S[i,j-r]+S[i-r]-S[i-r,j-r]+A[i,j].
#include<iostream>
using namespace std;
int dp[5010][5010];
int main()
{
int n, r;
cin >> n >> r;
int maxx = r, maxy = r;
for (int i = 0,x,y,w; i < n; i++) {
cin >> x >> y >> w;
x++, y++;
dp[x][y] += w;
maxx = max(maxx, x);
maxy = max(maxy, y);
}
for (int i = 1; i <= maxx; i++) {
for (int j = 1; j <= maxy; j++) {
dp[i][j] += dp[i][j - 1] + dp[i - 1][j] - dp[i-1][j-1];
}
}
int ans = 0;
for (int i = r; i <= maxx; i++) {
for (int j = r; j <= maxy; j++) {
ans = max(ans, dp[i][j] - dp[i - r][j] + dp[i - r][j - r] - dp[i][j - r]);
}
}
cout << ans ;
}
同理对于每一个边长为r的正方形,我们都有:
∑
x
=
i
−
r
+
1
i
∑
y
=
j
−
r
+
1
j
A
[
x
,
y
]
\displaystyle\sum_{x=i-r+1}^{i}\sum_{y=j-r+1}^{j} A[x,y]
x=i−r+1∑iy=j−r+1∑jA[x,y]=S[i,j]-S[i-r,j]-S[i,j-r]+S[i-r,j-r].
差分数组
B[1]=A[1],B[i]=A[i]-A[i-1] (2<=i<=n)
总要结论:
差分数组的前缀和就是原数组!!!
例题
一个长度为n的数列{a1,a2,…,an},每次可选择[l,r]的数都+1或-1,要让这些数字都相同,最少操作多少次,且最少操作下有几种可能的数字。
原理
求出a的差分数组b
从b1,b2,…bn+1中任选两个数的方法可分为四类:
1.选bi和bj,2<=i,j<=n.这种操作会改变b2,b3,…,bn中两个数的值.应该在保证bi和bj一正一负的前提下,尽量多的采取这种操作,更快地接近目标.
2.选b1和bj,其中2<=j<=n.
3.选bi和bn+1,其中2<=i<=n.
4.选b1和bn+1.因为没有意义故不这样做
p:差分数组的正数和,q:差分数组的负数和
次数:min(p,q)+|p-q|=max(p,q)
情况:|p-q|+1
ACWING100
代码:
#include<iostream>
using namespace std;
#define ll long long
const int maxn = 1e5 + 10;
ll a[maxn];
int main()
{
int n;
cin >> n ;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
ll zs = 0 , fs = 0;
for (int i = n; i > 1; i--) {
a[i] = a[i] - a[i - 1];
if (a[i] >= 0)zs += a[i];
else fs += -a[i];
}
cout << max(zs,fs) << endl << abs(zs - fs) + 1<< endl;
}
其他例题:ACWING101