前缀和与差分的使用技巧

前缀和与差分是算法中常用的技巧,可以有效的降低算法复杂度,一些题目看似是线段树的问题,实际可以通过前缀和与差分求解。相对于线段树,前缀和与差分代码更简洁。首先引用两篇博客:
[1] https://blog.csdn.net/XT_NOI/article/details/72715904
[2] https://blog.csdn.net/k_r_forever/article/details/81775899

最近做了一些相关的题目:
  1. 西南民族大学第十届校赛(同步赛),M题:HJ浇花,https://ac.nowcoder.com/acm/contest/322/M
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 2e6 + 5;
int cnt[maxn], prefix[maxn], a[maxn], n, l, r;
int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> l >> r;
		prefix[l] += 1;
		prefix[r + 1] -= 1;
	}
	for (int i = 1; i < maxn; i++)
		prefix[i] += prefix[i - 1];
	for (int i = 0; i < maxn; i++)
		cnt[prefix[i]]++;
	for (int i = 1; i <= n; i++)
		cout << cnt[i] << " ";
	return 0;
}
  1. 杭电OJ1556,Color the ball,http://acm.hdu.edu.cn/showproblem.php?pid=1556
#include <iostream>
#include <string.h>
using namespace std;

const int maxn = 100005;
int pmax[maxn];

int main()
{
	int N, a, b;
	while (cin >> N && N)
	{
		memset(pmax, 0, sizeof(pmax));
		for (int i = 1; i <= N; i++)
		{
			cin >> a >> b;
			pmax[a]++;
			pmax[b+1]--;
		}
		for (int i = 1; i <= N; i++)
		{
			pmax[i] += pmax[i - 1];
			if (i < N)
				cout << pmax[i] << " ";
			else
				cout << pmax[i] << endl;
		}
	}
	return 0;
}
  1. 杭电OJ5327,Olympiad,http://acm.hdu.edu.cn/showproblem.php?pid=5327
#include <iostream>
using namespace std;

int T, l, r,pmax[100005];

int check(int x)
{
	int digit[10] = { 0 };
	while (x)
	{
		int c = x % 10;
		if (digit[c])
			return 0;
		digit[c] = 1;
		x /= 10;
	}
	return 1;
}

int main()
{
	for (int i = 1; i <= 100005; i++)
		pmax[i] = pmax[i - 1] + check(i);

	cin >> T;
	while (T--)
	{
		cin >> l >> r;
		cout << pmax[r] - pmax[l - 1] << endl;
	}
	return 0;
}
  1. 杭电OJ5480,Conturbatio,http://acm.hdu.edu.cn/showproblem.php?pid=5480
    这道题是二维前缀和,实际上是将每一个車(x,y)提升到第一行和第一列
#include <cstdio>
#include <cstring>
using namespace std;

const int N = 1e5 + 5;
int x[N], y[N], t, n, m, p, q, x1, x2, y1, y2;

int main()
{
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d%d%d%d", &n, &m, &p, &q);
		memset(x, 0, sizeof(x));
		memset(y, 0, sizeof(y));
		for (int i = 1; i <= p; i++)
		{
			scanf("%d%d", &x1, &y1);
			x[x1] = y[y1] = 1;
		}
		for (int i = 2; i <= n; i++)
			x[i] += x[i - 1];
		for (int i = 2; i <= m; i++)
			y[i] += y[i - 1];
		for (int i = 1; i <= q; i++)
		{
			scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
			if (x[x2] - x[x1 - 1] == (x2 - x1 + 1) || y[y2] - y[y1 - 1] == (y2 - y1 + 1))
				printf("Yes\n");
			else
				printf("No\n");
		}
	}
	return 0;
}
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Researcher-Du

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值