[AGC028B] Removing Blocks
题意:
给定长度为 \(n\) 的序列 \(\{a_n\}\),现需将 \(n\) 个元素全部删除。
删除元素 \(i\) 的时候,设包括 \(i\) 的极长未被删除区间为 \([l,r]\) ,则代价为 \(\sum_{p=l}^r a_p\)
求 \(n!\) 种删除顺序的代价之和。
分析:
这类求 所有情况的代价,都可以这样求:
随机一个排列,求代价的期望 \(\times\) 情况数
考虑计算每个元素在一个固定顺序中,贡献到代价中的次数。
建立基于删除时间的小根堆笛卡尔树,则笛卡尔树上一个节点对答案的贡献是字数内 \(a_i\) 之和。
设 \(h_i\) 是 \(i\) 号点的贡献,令根节点深度为 \(1\) ,则代价之和为 \(\sum_{i=1}^n h_i \times a_i\) 。
现在要求的就是每一个 \(h_i\) 的期望 \(E(h_i)\) , 等价于计算有多少个 \(x\) 是 \(i\) 的祖先。
考虑一个排列: 若 \(x<i\) 且 \(x\) 是 \(i\) 的祖先,则 \(x,x+1,...i-1\) 都应该比 \(i\) 后删除,这样的方案数占总方案数的 \(\Large\frac{(i-x)!}{(i-x+1)!}=\Large\frac{1}{i-x+1}\)。
因为只有这 \(i-x+1\) 个元素的相对顺序是重要的,其中恰好有 \(\Large\frac{1}{i-x+1}\) 个排列满足 \(i\) 在最前面被删除。
同理 \(x>i\), 有 \(\Large\frac{1}{x-i+1}\) 的概率成立。
对于每一个 \(x<i,x>i\) ,都可以有这样的概率,因此有:
\[E(h_i)=\sum_{x=1}^{i-1}\frac{1}{i-x+1}+\sum_{x=i+1}^n\frac{1}{x-i+1}+1 \]设:
\[s_x=\sum_{i=1}^x \frac{1}{i} \]则:
\[E(h_i)=s_i+s_{n-i+1}-1 \]因此答案为:
\[n! \times \sum_{i=1}^n(s_i+s_{n-i+1}-1)\times a_i \]计算即可。
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5,mod=1e9+7;
int fac[N],inv[N],s[N];
int n,a[N],ans;
void init(int n){
fac[0]=fac[1]=1; inv[0]=inv[1]=1;
for(int i=2;i<=n;i++) fac[i]=fac[i-1]*i%mod;
for(int i=2;i<=n;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
for(int i=1;i<=n;i++) s[i]=(s[i-1]+inv[i])%mod;
}
signed main(){
cin>>n;
init(100000);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=n;++i) ans=(ans+(s[i]+s[n-i+1]-1)*a[i])%mod;//计算一次的期望
printf("%lld\n",ans*fac[n]%mod);
// system("pause");
return 0;
}