AGC028 B Removing Blocks 期望 逆元 前缀和

18 篇文章 0 订阅
7 篇文章 0 订阅

题目链接
题意:
给你 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=1najbj,最后再成一个 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(ij)+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[ni+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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值