ARC154E 做题记录

link

很强的题目!

我们求的就是一个数前面比他大的个数 \(-\) 后面比他小的个数。

我们仔细观察,可以注意到两者之间是有关联的

具体的,对于 \(i\) 和数字 \(p_i\),设 \(x\)\(p_{1...i-1}\) 中比 \(p_i\) 大的个数,那么右边比 \(p_i\) 大的个数为 \(n-p_i-x\),右边比 \(p_i\) 小的个数为 \(n-i-(n-p_i-x)=p_i-i+x\),两者相减得 \(i-p_i\)

所以我们要算的实际上是 \(E(\sum i(i-p_i))=\sum i^2 - E(\sum i\cdot p_i)\)

然后我们考虑 \(p_i\) 的最终所在位置的期望,而不是一味的求 \(i\) 位置上最终数字的期望。

\(p_i\) 被一次操作区间包含时,我们会发现它达到 \(j\)\(n-j+1\) 的概率都相等。

具体而言,到达位置 \(j\) 的概率为 \(\dfrac{\min(\min(i,j),n-\max(i,j)+1)}{i(n-i+1)}\),最好还是画个图,画个图就知道 \(j\)\(n-j+1\) 的概率相等。

所以被操作后的位置期望是 \(\dfrac{n+1}2\)

我们只需要算每个 \(p_i\) 至少一次被操作的概率和都没有被操作的概率。

总结一下:

  • 抓性质,找到不同东西之间的联系

  • 转化为每个数独立计算

  • 在更深入的推导中,若被卡壳,别忘了从其他的子角度入手

  • 观察操作的特点,并归纳

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define pir pair<ll,ll>
#define mkp make_pair
#define fi first
#define se second
#define mkp make_pair
#define pb push_back
using namespace std;
const ll maxn=2e5+10, mod=998244353;
ll n,m,a[maxn],ans,res;
ll power(ll a,ll b=mod-2){
	ll s=1; a%=mod;
	while(b){
		if(b&1) s=s*a%mod;
		a=a*a%mod; b>>=1;
	} return s;
}
int main(){
	scanf("%lld%lld",&n,&m);
	for(ll i=1;i<=n;i++){
		scanf("%lld",a+i);
	}
	ll d=power(n*(n+1)/2,m);
	for(ll i=1;i<=n;i++) ans=(ans+i*i)%mod;
	for(ll i=1;i<=n;i++){
		ll tmp=((i-1)*i/2+(n-i)*(n-i+1)/2)%mod*power(n*(n+1)/2)%mod;
		tmp=power(tmp,m);
		res=(res+((mod-mod/2)*(n+1)%mod*(mod+1-tmp)%mod+tmp*i%mod)*a[i])%mod;
	}
	ans=(ans-res+mod)*d%mod;
	printf("%lld",ans);
	return 0;
}
posted @ 2024-03-29 07:32  Sktn0089  阅读(8)  评论(0编辑  收藏  举报