1. 程式人生 > >AGC028 B Removing Blocks 期望 逆元 字首和

AGC028 B Removing Blocks 期望 逆元 字首和

題目連結
題意:
給你 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;
}