AGC028 B Removing Blocks 期望 逆元 前缀和

版权声明:本文为博主原创文章,可以转载但是必须声明版权。 https://blog.csdn.net/forever_shi/article/details/83051609

题目链接
题意:
给你 n n 个数,现在有 n n 次操作,每次操作选择一个未选择的数,然后加上从它到它后面最后一个连续没选过的数的权值和,并标记这个数为选过。我们发现,我们有 n ! n! 种可能的操作,求这 n ! n!
种操作得到的权值和的和。

题解:
atcoder真的是好题无限啊!这题真不错,我一开始想这题算每一个数对答案的贡献,想尝试用组合数,发现做不出来。然后感慨这题似乎可以出成期望题啊,然后去看题解,发现真的是用期望做。。

我们设 p ( i , j ) p(i,j) i i j j 这个区间完好,在操作时选了 i i 的概率,那么对于所有的 j j ,我们设 j j 对答案的期望贡献次数是 b j b_j j j 这个位置的值是 a j a_j ,那么有 b j = i = 1 n p ( i , j ) b_j=\sum_{i=1}^np(i,j) ,对于随机操作,我们期望得到的答案就是 i = 1 n a j b j \sum_{i=1}^na_j*b_j ,最后再成一个 n ! n! 就是最后的答案了。

我们发现, i i p ( i , j ) p(i,j) 中最先出现的概率相当于是在区间 [ i , j ] [i,j] 中先选出 i i 的概率,即 1 a b s ( i j ) + 1 \frac{1}{abs(i-j)+1} ,那么我们对 1 1 + 1 2 + . . . + 1 n ( m o d    n ) \frac{1}{1}+\frac{1}{2}+...+\frac{1}{n}(\mod n) 求前缀和,当然需要先 O ( n ) O(n) 的求逆元。然后我们可以算出 j j 前面(不包含 j j 本身)的 p ( i , j ) p(i,j) 的前缀和 s [ i ] 1 s[i]-1 j j 后面(包含 j j 本身)的所有 p ( i , j ) p(i,j) 的和 s [ n i + 1 ] s[n-i+1] 。其中前一个减1是因为要不包含 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;
}

猜你喜欢

转载自blog.csdn.net/forever_shi/article/details/83051609
今日推荐