emmm..终于ac了,这里介绍一下标程做法,大佬的分治做法我也看不太懂,码风完全不一样.
标程就是从后往前计算贡献,算出贡献的付出,最后保留的贡献就是f[n].

#include <bits/stdc++.h>
typedef long long ll;
const ll mod=998244353;
const int N=5e5+5;
struct vv{
    ll h,id;//高度和位子.
}w[N];
ll n,dis[N],g[N],f[N],sum[2][N];//第1维维护个数,第二维维护权值.

ll qp(ll a,ll b)
{
    ll res=1;
    while(b)
    {
        if(b&1)    res=res*a%mod;
        b>>=1;
        a=a*a%mod;
    }return res;
}

ll iv(ll x) { return qp(x,mod-2); }

bool cmp(vv a,vv b)  { return a.h<b.h;  }

ll lowbit(ll x)  { return x&(-x); }

void add(ll pos,ll val,int op)
{
    while(pos<=n)
    {
        sum[op][pos]+=val;
        pos+=lowbit(pos);
    }
}

ll query(ll pos,int op)
{
    ll res=0;
    while(pos)
    {
        res+=sum[op][pos];
        pos-=lowbit(pos);
    }return res;
}

ll ask(ll pos)//查询前面所有点到这个点的距离.
{
    ll res=0;
    //询问在它前面的距离.
    res=((res+query(pos-1,0)*pos-query(pos-1,1))%mod+mod)%mod;
    //询问在它后面的距离.
    res=((res+query(n,1)-query(pos,1)-(query(n,0)-query(pos,0))*pos)%mod+mod)%mod;
    return res;
}

signed main()
{
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&w[i].h);
        w[i].id=i;
    }
    std::sort(w+1,w+1+n,cmp);
    //进行dp.
    int cnt=0;//统计前面所有的平均值.
    for(int i=1;i<=n;)
    {
        int j=i,now=0;//单纯统计当前转移的g[i]平均值.
        while(w[i].h==w[j].h)   j++;
        for(int k=i;k<j;k++)
        {
            dis[k]=(ask(w[k].id)%mod+mod)%mod;
            g[k]=((cnt+dis[k])%mod+mod)%mod;
            g[k]=((g[k]*iv(i-1))%mod+mod)%mod;
            now=((now+g[k])%mod+mod)%mod;
        }
        for(int k=i;k<j;k++)    {int pos=w[k].id;add(pos,1,0);add(pos,pos,1);}
        for(int k=i;k<j;k++)
        {
            ll odd=((now-g[k]+ask(w[k].id)-dis[k])%mod+mod)%mod;
            f[k]=((iv(j-2)*(i-1)%mod)*g[k]%mod+iv(j-2)*odd%mod+mod)%mod;
            cnt=((cnt+f[k])%mod+mod)%mod;
        }
        //概率dp都是倒过来dp的.
        i=j;
    }
    printf("%lld\n",f[n]);
}