版权声明:本文为博主原创文章,可以转载但是必须声明版权。 https://blog.csdn.net/forever_shi/article/details/83051609
题目链接
题意:
给你
个数,现在有
次操作,每次操作选择一个未选择的数,然后加上从它到它后面最后一个连续没选过的数的权值和,并标记这个数为选过。我们发现,我们有
种可能的操作,求这
种操作得到的权值和的和。
题解:
atcoder真的是好题无限啊!这题真不错,我一开始想这题算每一个数对答案的贡献,想尝试用组合数,发现做不出来。然后感慨这题似乎可以出成期望题啊,然后去看题解,发现真的是用期望做。。
我们设 为 到 这个区间完好,在操作时选了 的概率,那么对于所有的 ,我们设 对答案的期望贡献次数是 , 这个位置的值是 ,那么有 ,对于随机操作,我们期望得到的答案就是 ,最后再成一个 就是最后的答案了。
我们发现, 是 中最先出现的概率相当于是在区间 中先选出 的概率,即 ,那么我们对 求前缀和,当然需要先 的求逆元。然后我们可以算出 前面(不包含 本身)的 的前缀和 和 后面(包含 本身)的所有 的和 。其中前一个减1是因为要不包含 本身。于是就可以用上面说的方法求出答案了。
代码:
#include <bits/stdc++.h>
using namespace std;
const long long mod=1e9+7;
int n;
long long a[100010],ni[100010],s[100010],ans,jie[100010];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
ni[1]=1;
for(int i=2;i<=n;++i)
ni[i]=(mod-mod/i)*ni[mod%i]%mod;
for(int i=1;i<=n;++i)
s[i]=(s[i-1]+ni[i])%mod;
for(int i=1;i<=n;++i)
ans=(ans+s[n-i+1]*a[i]%mod+(s[i]-1)*a[i]%mod)%mod;
jie[0]=1;
for(int i=1;i<=n;++i)
jie[i]=jie[i-1]*i%mod;
ans=(ans*jie[n])%mod;
printf("%lld\n",ans);
return 0;
}