题目链接:http://codeforces.com/contest/1096/problem/F
题意:给你一个n个数的排列,但是在这个排列中有一些数字被-1覆盖。问你这个排列中逆序对的期望是多少。
自己想也只能想到一个部分,还是去网上看了人家的题解做出来的,其实也不是特别难,缺少想法吧。
做法:
这个逆序对的个数由四个部分组成,假设我们有m个未知数。
1.已知数和已知数之间的逆序对。
有板子,也可以用树状数组直接做,每次在找到一个数之后去统计有多少个比它大的数字已经出现,然后把这个数也加紧sum数组;
2.未知数和未知数之间的逆序对。
因为每一对数字之间的逆序对期望为0.5,又随意取出一对数有,也就是m*(m-1)/2种,所以这个数量就是m*(m-1)/4种;
3.未知数在前,已知数在后的逆序对。
假设我们已经统计好了对于一个数x,有have[x]个小于它的数(因为是排列,所以已经出现过的数不可能再出现,所以没有等于的情况)。并且我们也统计了对于第i位的数,前面有k个空格,那么对于第i位的已知数来说,这个情况产生的逆序对就是,因为对于前面的k个空格,每个都可以填入(m-have[a[i]])中的一个数,其他的数字是全排列,分母就是所有数的全排列。
4.已知数在前,未知数在后的逆序对。
思路同情况3,我们在知道了前面有k个空格之后,那么后面就有(m-k)个空格,得到有have[a[i]]个数比第i位上的数小之后,这个情况产生的逆序对就是
代码如下。
#include <bits/stdc++.h>
#define debug printf("####\n")
#define DEBU
using namespace std;
typedef long long ll;
const int maxn=200055;
const ll mod=998244353;
int sum[maxn+10];
ll quick(ll a,ll b){
ll ans=1;
while(b){
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b/=2;
}
return ans;
}
ll inv(ll x){
return quick(x,mod-2);
}
int lowbit(int x){
return x&(-x);
}
void add(int x){
while(x<maxn){
sum[x]++;
x+=lowbit(x);
}
}
ll query(int x){
ll ans=0;
while(x){
ans+=(ll)sum[x];
x-=lowbit(x);
}
return ans;
}
int n;
bool vis[maxn];
ll ty1,ty2,ty3,a[maxn],hav[maxn],m;
//ty1为情况1,ty2为情况2,ty3则为两种情况的和
int main(){
scanf("%d",&n);
ll inv4=inv(4);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
if(a[i]!=-1){
ty1=(ty1+query(maxn)-query(a[i]))%mod;
vis[a[i]]=1;
add(a[i]);
}
else m++;
}
ty2=m*inv4%mod*(m-1)%mod;
int now=0; ll invm=inv(m);
for(int i=1;i<=n;i++){
if(!vis[i]) now++;
else hav[i]=now;
}
ll kong=0;
for(int i=1;i<=n;i++){
if(a[i]!=-1){
ty3=(ty3+hav[a[i]]*(m-kong)%mod*invm%mod+(m-hav[a[i]])*kong%mod*invm%mod)%mod;
}
else kong++;
}
printf("%lld\n",(ty1+ty2+ty3)%mod);
return 0;
}
顺便贴一个n个数的数列逆序对个数计算的板子
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=100005;
int a[maxn],b[maxn],n;
long long ans;
void mm(int st,int mid,int en){
int i=st,k=st,j=mid+1;
while(i<=mid&&j<=en){
if(a[i]<=a[j]){
b[k++]=a[i++];
}
else {
ans+=j-k;
b[k++]=a[j++];
}
}
while(i<=mid) b[k++]=a[i++];
while(j<=en) b[k++]=a[j++];
for(i=st;i<=en;i++)
a[i]=b[i];
}
void ms(int st,int en){
if(st<en){
int mid=st+en>>1;
ms(st,mid);
ms(mid+1,en);
mm(st,mid,en);
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
ms(1,n);
printf("%lld\n",ans);
return 0;
}