题目链接
题意:
给你
n
n
n个数,现在有
n
n
n次操作,每次操作选择一个未选择的数,然后加上从它到它后面最后一个连续没选过的数的权值和,并标记这个数为选过。我们发现,我们有
n
!
n!
n!种可能的操作,求这
n
!
n!
n!
种操作得到的权值和的和。
题解:
atcoder真的是好题无限啊!这题真不错,我一开始想这题算每一个数对答案的贡献,想尝试用组合数,发现做不出来。然后感慨这题似乎可以出成期望题啊,然后去看题解,发现真的是用期望做。。
我们设 p ( i , j ) p(i,j) p(i,j)为 i i i到 j j j这个区间完好,在操作时选了 i i i的概率,那么对于所有的 j j j,我们设 j j j对答案的期望贡献次数是 b j b_j bj, j j j这个位置的值是 a j a_j aj,那么有 b j = ∑ i = 1 n p ( i , j ) b_j=\sum_{i=1}^np(i,j) bj=∑i=1np(i,j),对于随机操作,我们期望得到的答案就是 ∑ i = 1 n a j ∗ b j \sum_{i=1}^na_j*b_j ∑i=1naj∗bj,最后再成一个 n ! n! n!就是最后的答案了。
我们发现, i i i是 p ( i , j ) p(i,j) p(i,j)中最先出现的概率相当于是在区间 [ i , j ] [i,j] [i,j]中先选出 i i i的概率,即 1 a b s ( i − j ) + 1 \frac{1}{abs(i-j)+1} abs(i−j)+11,那么我们对 1 1 + 1 2 + . . . + 1 n ( m o d    n ) \frac{1}{1}+\frac{1}{2}+...+\frac{1}{n}(\mod n) 11+21+...+n1(modn)求前缀和,当然需要先 O ( n ) O(n) O(n)的求逆元。然后我们可以算出 j j j前面(不包含 j j j本身)的 p ( i , j ) p(i,j) p(i,j)的前缀和 s [ i ] − 1 s[i]-1 s[i]−1和 j j j后面(包含 j j j本身)的所有 p ( i , j ) p(i,j) p(i,j)的和 s [ n − i + 1 ] s[n-i+1] s[n−i+1]。其中前一个减1是因为要不包含 j j j本身。于是就可以用上面说的方法求出答案了。
代码:
#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;
}