题目大意:
有n个点,每个点被点击的成功率为p[i]/100,如果有连续的x点成功被点击,你将获得x^m次方的分数,问你在已知所有点被点击成功的概率的情况下,问你最后获得分数的期望。
解题思路:
思路的话其实我感觉对于期望题我就只会对单位求贡献,这个题目也是一样的。就是从这个位置开始连续x点成功的概率*获得分数,算起来也很简单,假设从 i 开始 连续 x 个成功的概率 ,其实就是 i-1 失败的概率 * i开始连续x个成功的概率*之后一个点失败的概率。这样的话算法的复杂度是 n^2,与m就没有关系了,但是出题人说有另一种n*m的解法,目前还不是很懂,以后学习一下。
Ac代码:
#include<bits/stdc++.h>
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");
}