其他分享
首页 > 其他分享> > [AGC028B] Removing Blocks

[AGC028B] Removing Blocks

作者:互联网

[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;
}

标签:AGC028B,frac,删除,int,Removing,sum,times,Blocks,代价
来源: https://www.cnblogs.com/guanlexiangfan/p/15412216.html