牛客网暑期ACM多校训练营(第九场)E:Music Game(单位求贡献)

 

题目大意:

有n个点,每个点被点击的成功率为p[i]/100,如果有连续的x点成功被点击,你将获得x^m次方的分数,问你在已知所有点被点击成功的概率的情况下,问你最后获得分数的期望。

 

解题思路:

思路的话其实我感觉对于期望题我就只会对单位求贡献,这个题目也是一样的。就是从这个位置开始连续x点成功的概率*获得分数,算起来也很简单,假设从 i 开始 连续 x 个成功的概率 ,其实就是 i-1 失败的概率 * i开始连续x个成功的概率*之后一个点失败的概率。这样的话算法的复杂度是 n^2,与m就没有关系了,但是出题人说有另一种n*m的解法,目前还不是很懂,以后学习一下。

 

Ac代码:

#include
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=1e9+7;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
int n,m;
ll a[maxn],b[maxn],inv[maxn],val[maxn];
int main()
{
    scanf("%d%d",&n,&m);
    b[0]=1; b[n+1]=1; val[0]=1; inv[0]=1;   //注意inv[0]=1 被坑了好久
    ll gk=powmod(100,mod-2);    //对100先预处理逆元
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        b[i]=b[i-1]*a[i]%mod*gk%mod;    //求出连续成功的前缀和
        if(b[i]==0) inv[i]=1,b[i]=1;    //这里注意要特殊处理
        else inv[i]=powmod(b[i],mod-2);
        val[i]=powmod(i,m);
    }
    ll res=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]==0) continue;   //这里注意也要处理一下
        for(int j=i;j<=n;j++)
        {
            if(a[j]==0) break;  //同上
            res=(res+(100-a[i-1])%mod*gk%mod*b[j]%mod*inv[i-1]%mod*(100-a[j+1])%mod*gk%mod*val[j-i+1]%mod)%mod; //加上它对答案的贡献
        }
    }
    res=(res+mod)%mod;
    printf("%lld\n",res);
    //system("pause");
}

 

你可能感兴趣的:(思维)