牛客网暑假训练第九场——E Music Game(概率期望)

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
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.
示例1
输入
3 4
50 50 50
输出
750000020
说明
000 0
001 1
010 1
011 16
100 1
101 2
110 16
111 81

The exact answer is (0 + 1 + 1 + 16 + 1 + 2 + 16 + 81) / 8 = 59/4.
As 750000020 * 4 mod 1000000007 = 59
You should output 750000020.
备注:
If you don’t know how to output a fraction mod 1000000007,
You may have a look at https://en.wikipedia.org/wiki/Modular_multiplicative_inverse

题意:在一个长度为n的01串中,给出每个位置是1的概率,现在连续的1长度为x,如果存在连续的1,那么得分即为所有x的m次方的加和,求得分的期望。

由题可知若长度n为3时
每个位置出现1的概率是50%,那么就有01的全排列中组合,其中出现1连续的1的长度有0,1,2,3。那么m等于4时即这些长度的4次方之和,求和结果除以概率即期望值。

首先枚举那么多01的情况再去计算连续1的长度是不可能的。因此对于每种情况我们定量分析。
如一个很复杂的011101101101
可以发现其连续1的段有长度为3,2,2,1的,我们只观察最右边的01。
可以知道,当一组连续的1左右两边都为0或者触碰到边界时,才作为“连续”而存在,否则连续的1长度将更长。在定量分析最右的01时,我们可以计算出其出现概率是i位pi和第i-1位 100-pi【因为是0】

那么剩余部分不管。我们对剩余部分进行全排列,即 xxxxxxxxxx 01,忽略了左边复杂的0111011011情况,只计算右边的01情况。意思是,无论左边如何变化,只要右边是01,那么出现的概率可以确定,获得的分数可以确定,即1^m,这样的形式可以在任何情况中出现。至于被忽略部分的概率,因为是全排列,那么肯定是1,因为10的情况全部被算在全排列中了,所以任何可能发生的情况被算在内时概率必定是1。

接着,我们将01进行左移,即 xxxxxxxx 010 x,使得这个1的长度在串中每个位置都出现一下,在此计算在不同位置出现的概率和得到的价值,对其进行乘积和加和。

这样长度为1的就枚举完了,可以得到长度1在任何位置的概率及分数加和。然后枚举长度为2时的所有情况,同样只考虑类似0110的串在每个位置存在的概率和分数,在边缘时为011或110。对这样的串枚举每一个出现位置。

这样枚举所有长度以及所有位置,进行求和即可得到最终期望。

dp【i】【j】表示,在第i个位置开始出现连续的1,其长度为j的概率。即表示了一段区间内可能出现1的概率。用这个结果,再乘上i-1和i+j两边的0出现概率,即得到该长度的概率,最后乘上其权值j^m即可。

#include
#define LL long long
using namespace std;
const int maxn=1005;
const int mod=1000000007;
LL qp(LL a,LL b)
{
    LL res=1;
    while(b)
    {
        if(b&1)res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
LL n,m,p[maxn],fac[maxn],zep[maxn],dp[maxn][maxn];
void init(int n,int m)///预处理长度为1~n的m次方
{
    fac[1]=fac[0]=1;
    for(int i=2;i<=n;i++) fac[i]=qp(i,m);
}
LL inv=qp(100,mod-2);///概率分母100的逆元
int main()
{
    while(scanf("%lld%lld",&n,&m)!=EOF)
    {
        init(n,m);
        LL ans=0;
        zep[n+1]=p[n+1]=zep[0]=p[0]=1;///初始化在最左边和最右边出现0的概率,因为不存在这个值,所以必定是0,概率为1
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&p[i]);
            zep[i]=(100-p[i])*inv%mod;///计算该位置出现0的概率的逆元
            p[i]=p[i]*inv%mod;///该位置出现1的概率的逆元
            dp[i][0]=1;///长度为0时概率为1,表示不对后面的概率产生影响
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;i+j<=n+1;j++)
            {
                dp[i][j]=dp[i][j-1]*p[i+j-1]%mod;
                LL tmp=dp[i][j]*zep[i-1]%mod*zep[i+j]%mod;
                ans=(ans+(tmp*fac[j])%mod)%mod;
            }
        }
        printf("%lld\n",ans%mod);
    }
}

你可能感兴趣的:(动态规划,暴力)