CF891E Lust

题意:给定长度为 n 序列 a,每次随机选择 i[1,n],将 r 加上 jiaj,然后让 ai 减 1。问 k 次操作后,r 的期望。n5000k109,对 109+7 取模。

首先给出一个结论:

r=i=1naii=1nai

表示前后 ai 乘积的变化量。这个可以通过分每一步看来得到,既然单步是正确的,那么合并起来也是正确的。

现在显然是求变化后的期望。

考虑使用 EGF 计算每一步改变的哪一个位置,然后合并。单个的 EGF 可以写作:i=0xii!(ai)

那么最后变化后的期望就是:

k!nk[xk]i=1nj=0xjj!(ajx)

不是封闭形式不好计算,考虑对每一个 i=0xii!(ai) 变换来尝试得到封闭形式:

j=0xjj!(aj)=j=0xjaj!j=0xjjj!=aexj=1xxj1(j1!)=(ax)ex

这样就变成的封闭形式。

乘起来可以得到:

k!nk[xk]enxi=1n(aix)

后面这个式子可以 O(nlog2n) 计算,但是直接 O(n2) DP 计算每一位也不是不行。

下面对后面是贡献 xtxk 的系数计算:

k!nk×ctnkt(kt)!

虽然 k 很大,但是 t 不大,这些都可以约到 t 项,而且不同的 t 可以递推计算,所以这不是难事,可以在 O(n) 或者 O(nlogk) 的时间内求出所有 t[0,n] 的贡献。

总时间复杂度 O(n2)狗都不写 MTT。注意代码中的 f[t] 求的是 nt 的系数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int main()
{
std::cin >> n >> k;
for (int i = 1; i <= n; ++ i) std::cin >> a[i];
f[0] = 1;
for (int i = 1; i <= n; ++ i)
for (int j = i - 1; ~j; -- j)
f[j + 1] = (f[j + 1] + (LL) f[j] * a[i]) % Mod;

int res = 0, cur = k;
for (int i = 1; i <= n && i <= k; ++ i)
{
if (!(i & 1))
res = (res + (LL) (Mod - cur) * qpow(n, k - i) % Mod * f[n - i]) % Mod;
else res = (res + (LL) cur * qpow(n, k - i) % Mod * f[n - i]) % Mod;
cur = (LL) cur * (k - i) % Mod;
}
res = (LL) res * qpow(n, Mod - 1 - k) % Mod;
// adj(res = f[n] - res);
std::cout << res << '\n';
return 0;
}

Related Issues not found

Please contact @mydcwfy to initialize the comment