ARC154E 做題記錄

Sktn0089發表於2024-03-29

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

相關文章