题目描述
维护一个正整数多重集合 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=1kCkiaibk−i
这时我们可以发现,若已知 ( ∑ 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
#include
#include
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
*/