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