小w的糖果 (差分)

题目链接: 小w的糖果

大致题意

有一个长度为 n n n的数组, 初始情况数组内所有的元素均为 0 0 0, 进行 m m m次如下三种操作:
① 给 [ p o s , n ] [pos, n] [pos,n]区间所有元素+1
② 给 [ p o s , n ] [pos, n] [pos,n]区间的所有元素加上一个首项为1, 公差也为1的等差数列.
③ 给 [ p o s , n ] [pos, n] [pos,n]区间的所有元素加上一个 1 , 4 , 9 , 16 , . . . 1, 4, 9, 16, ... 1,4,9,16,...的平方数列.

最终输出序列中每个位置的值 m o d   1 0 9 + 7 mod \ 10^9 + 7 mod 109+7.

解题思路

注: 下文所提到的等差数列均指首项和公差均为1的等差数列.

我们发现题目中实际上是在进行一系列的区间加操作, 最终再输出序列.
我们比较容易想到用差分的方式来维护序列.

但是我们区间加操作, 只能对于一个区间加上相同的数字, 是不能直接加等差数列 和 平方数列的.

现在有等差数列 1 2 3 4 5 6 7
我们求出其差分数组: 1 1 1 1 1 1 1
再次对差分数组求差分: 1 0 0 0 0 0 0

这相当于什么? 
如果我们假设差分数组为b[]
如果我想给[1, 7]加上一个等差数列, 我只需要在b[1]的位置加上1, b[8]的位置减去1.
然后我对b数组进行求前缀和, 此时我们就能得到一个{ 1 1 1 1 1 1 1 }序列.
然后再求一次前缀和, 我们就得到了{ 1 2 3 4 5 6 7 }序列.

因此我们的出结论: 如果我想给一个序列加上一个等差数列, 我们可以通过对差分数组求两次前缀和的方式得到.


同理我们考虑对于序列加平方数列的操作
原序列: 1 4 9 16 25 36 49
一次差分: 1 3 5 7 9 11 13
两次差分: 1 2 2 2 2 2 2
三次差分: 1 1 0 0 0 0 0

这又相当于什么?
如果我们假设差分数组为c[]
如果我想给[1, 7]加上一个平方数列, 我们需要对于c[1]1, c[2]1, 然后对于c[8]的位置-2
最后求三次前缀和即可.

因此我们同样的出结论: 如果我想给一个序列加上一个平方数列, 我们可以通过对差分数组求三次前缀和的方式得到.

AC代码

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 1E5 + 10, mod = 1E9 + 7;
int a[N], b[N], c[N]; //分别对应三种操作的差分数组.
void fact(int a[], int n) { rep(i, n) a[i] = (a[i - 1] + a[i]) % mod; }
int main()
{
	int t; cin >> t;
	while (t--) {
		int n, m; scanf("%d %d", &n, &m);
		rep(i, n + 1) a[i] = b[i] = c[i] = 0;

		rep(i, m) {
			int tp, pos; scanf("%d %d", &tp, &pos);
			if (tp == 1) a[pos]++, a[n + 1]--;
			else if (tp == 2) b[pos]++, b[n + 1]--;
			else c[pos]++, c[pos + 1]++, c[n + 1] -= 2;
		}

		fact(a, n);
		rep(i, 2) fact(b, n);
		rep(i, 3) fact(c, n);

		rep(i, n) printf("%d%c", (0ll + a[i] + b[i] + c[i]) % mod, " \n"[i == n]);
	}

	return 0;
}

END

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

逍遥Fau

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

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

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

打赏作者

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

抵扣说明:

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

余额充值