前缀和与差分

前缀和数组:
S[i] = ∑ j = 1 i A [ j ] \displaystyle\sum_{j=1}^{i} A[j] j=1iA[j]
sum(l.r)= ∑ i = l r A [ i ] \displaystyle\sum_{i=l}^{r} A[i] i=lrA[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=1iy=1jA[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=ir+1iy=jr+1jA[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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值