#3974. 数据结构(set)

题目描述
维护一个正整数多重集合 SS,初始为空,支持两个操作:

插入:插入一个新数

修改:令集合中所有数加 11

每次操作结束后,计算 SS 中所有数的 kk 次方和,kk 预先给定。和可能很大,你只需要输出它对10^9+710
9
+7的余数即可。

输入格式
第一行两个数 MM,kk,其中 MM 表示操作次数。

接下来 MM 行,每行可能为以下两种之一:

0\ x0 x ,表示插入一个大小为 xx 的新元素。

11 ,表示令集合 SS 里所有数加一。

输出格式
输出 MM 行,第 ii 行表示第 ii 次操作结束之后,SS 中所有数的 kk 次方和。

样例
样例输入
3 2
0 1
0 1
1
样例输出
1
2
8
样例解释
第一次操作后,集合为 11 。
第二次操作后,集合为 1 \ 11 1 。
第三次操作后,集合为 2 \ 22 2 。

数据范围与提示
对全部的测试数据,M\leq 2\times 10^5M≤2×10
5
,k\leq 50k≤50。
对于10%10%的数据,k=1k=1;
对于20%20%的数据,M\leq 3000M≤3000;
对于20%20%的数据,k=2k=2;
对于20%20%的数据,k=3k=3;
对于30%30%的数据,无特殊限制。

来源
2018年10月hnsdfz集训

题解:
首先可得
( a + b ) k = ∑ i = 1 k C k i a i b k − i (a+b)^k=\sum_{i=1}^kC^i_ka^ib^{k-i} (a+b)k=i=1kCkiaibki
这时我们可以发现,若已知 ( ∑ i = 1 n x ) j (\sum_{i=1}^nx)^j (i=1nx)j,可以 O ( k ) O(k) O(k)地算出 a n s ans ans
所以我们只需确保所有 a = x a=x a=x所搭配的 b b b相同即可。
O ( n k ) O(nk) O(nk)

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long ll;
const int maxn = 2e5;
const int maxk = 50;
const int mod = 1e9 + 7;

int n, k, del;
ll c[maxk + 5][maxk + 5], sum[maxn + 5];

int main() {
	scanf("%d %d", &n, &k);
	for (int i = 0; i <= k; i++) c[i][0] = 1;
	for (int i = 1; i <= k; i++)
		for (int j = 1; j <= i; j++) c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
	while (n--) {
		int op; ll x;
		scanf("%d", &op);
		if (op) del++;
		else {
			scanf("%lld", &x); x-= del;
			ll res = 1;
			for (int i = k; i >= 0; i--) sum[i] = (sum[i] + res) % mod, res = res * x % mod; 
		}
		ll ans = 0, res = 1;
		for (int i = 0; i <= k; i++) {
			ans = (ans + c[k][i] * sum[i] % mod * res % mod + mod) % mod;
			res = res * del % mod;
		}
		printf("%lld\n", ans);
	}	
	return 0;
}
/*
5 1
0 5
1 
1
1
1
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值