题目:https://www.nowcoder.com/acm/contest/147/E
Niuniu likes to play OSU!
We simplify the game OSU to the following problem.
Given n and m, there are n clicks. Each click may success or fail.
For a continuous success sequence with length X, the player can score X^m.
The probability that the i-th click success is p[i]/100.
We want to know the expectation of score.
As the result might be very large (and not integral), you only need to output the result mod 1000000007.
输入描述:
The first line contains two integers, which are n and m.
The second line contains n integers. The i-th integer is p[i].
1 <= n <= 1000
1 <= m <= 1000
0 <= p[i] <= 100
输出描述:
You should output an integer, which is the answer.
sol:
这个题有 的做法,这里不多加讨论。说下从bls学到的用第二类 数优化计算 的方法。
1.考虑朴素的dp
设
为最长连续成功后缀的长度。设
为考虑前i次点击,
的期望。
由二项式定理可知
从而得到转移方程
设 为 的得分期望,由
则有
合并起来就是
这样做的复杂度是
2.用Stirling数优化
先放一个结论
也可以写为
这个可以在组合数学的教材里找到。
表示n的下阶乘,等价于 。 表示第二类 数
那么我们可以将维护 的期望 转换到维护 的期望上去。
同样的,我们设最长成功后缀的长度为 ,设 为 考虑到第i 位后 的期望,设 为所有 的期望。
由杨辉三角:
可得
同理可得
至此,这道题就可以能够在 的时间内完成.
code:
#include <bits/stdc++.h>
using namespace std;
int n, m, mod = 1000000007;
long long p[1020];
long long a[1020][1020];
long long b[1020][1020];
long long s[1020][1020];
long long f[1020];
typedef long long ll;
int main() {
scanf("%d%d", &n, &m);
s[0][0] = 1;
for (int i = 0; i <= m; i++) {
for (int j = 1; j <= i; j++) {
s[i][j] = (s[i - 1][j - 1] + j * s[i - 1][j]) % mod;
}
}
for (int i = f[0] = 1; i <= m; i++) {
f[i] = f[i - 1] * i % mod;
}
a[0][0] = 1;
for (int i = 1; i <= n; i++) {
scanf("%lld", &p[i]);
p[i] = p[i] * 570000004 % mod;
a[i][0] = 1;
for (int j = 1; j <= m; j++) {
a[i][j] = a[i-1][j] + a[i-1][j - 1];
a[i][j] *= p[i];
a[i][j] %= mod;
b[i][j] = p[i] * a[i-1][j-1];
b[i][j] %= mod;
b[i][j] += b[i-1][j];
b[i][j] %= mod;
}
}
long long z = 0;
for (int i = 1; i <= m; i++) {
z = (z + b[n][i] * f[i] % mod * s[m][i]) % mod;
}
printf("%lld\n", z);
return 0;
}