CF1096F Inversion Expectation
令 \(m\) 为 \(-1\) 的个数
答案分为三部分计算:
\(-1\to -1,-1\to other,other\to other\)
\[-1\to-1:\dfrac{m*(m-1)}{4}(\texttt{每一对之间期望}\dfrac{1}{2})\\
other\to other:\texttt{树状数组/归并排序裸题,求逆序对个数}
\]
难点在于 \(-1\to other\)
想想有啥可以利用的条件。
发现我们可以知道比每个不是 \(-1\) 的 \(i\) 小的不是 \(-1\) 的有几个,设为 \(cnt_i\)
那么形如
\([-1,\cdots,x]\) 的贡献就是 \(x\) 左边 \(-1\) 的个数乘上 \(\dfrac{m-(a_i-cnt_{a_i})}{m}\)
\([x,\cdots,-1]\) 的贡献就是 \(x\) 右边 \(-1\) 的个数乘上 \(\dfrac{a_i-cnt_{a_i}}{m}\)
加起来就是答案了。
快速幂写挂调了 \(1\) 小时身败名裂
大样例:
Input
10
-1 2 -1 4 5 -1 10 -1 9 -1
Output
199648886
#include<bits/stdc++.h>
typedef long long LL;
typedef double db;
#define pb(x) push_back(x)
#define mkp(x,y) make_pair(x,y)
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
//char buf[1<<21],*p1=buf,*p2=buf;
inline int read() {
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
return x*f;
}
const int N=200005;
const int mod=998244353;
int n,a[N],tr[N],m,ans,cnt[N];
void add(int x,int d){
for(int i=x;i<=n;i+=i&-i)tr[i]+=d;
}
int ask(int x){
int res=0;
for(int i=x;i>0;i-=i&-i)res+=tr[i];
return res;
}
void fmod(int&x){
x+=x>>31&mod,x-=mod,x+=x>>31&mod;
}
int qpow(int x,int y,int ret=1){
for(;y;y>>=1,x=1ll*x*x%mod) if(y&1)
ret=1ll*ret*x%mod; return ret;
}
signed main(){
n=read();
for(int i=1;i<=n;++i)a[i]=read(),m+=!~a[i];
ans=1ll*m*(m-1)/2%mod*((mod+1)>>1)%mod;
for(int i=n;i>=1;--i)if(~a[i])fmod(ans+=ask(a[i])),add(a[i],1),++cnt[a[i]];
for(int i=1;i<=n;++i)cnt[i]+=cnt[i-1];
int sum=0;
for(int i=1,t=0;i<=n;++i)
if(~a[i])fmod(sum+=1ll*t*(m-a[i]+cnt[a[i]])%mod);
else ++t;
for(int i=n,t=0;i>=1;--i)
if(~a[i])fmod(sum+=1ll*t*(a[i]-cnt[a[i]])%mod);
else ++t;
fmod(ans+=1ll*sum*qpow(m,mod-2)%mod);
std::cout<<ans<<'\n';
return 0;
}
路漫漫其修远兮,吾将上下而求索