Loading

CF1096F Inversion Expectation

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;
}
posted @ 2020-10-10 19:34  zzctommy  阅读(69)  评论(0编辑  收藏  举报