1. 程式人生 > >Codeforces 1096F(dp + 樹狀數組)

Codeforces 1096F(dp + 樹狀數組)

逆序對 貢獻 lap 數量 comm type int rst else

題目鏈接

題意:

對於長度為$n$的排列,在已知一些位的前提下求逆序對的期望

思路:

將答案分為$3$部分

$1.$$-1$與$-1$之間對答案的貢獻。由於逆序對考慮的是數字之間的大小關系,故假設$-1$的數量為$cnt$,可以等效成求長度為$cnt$的排列的逆序對期望。設$dp[i]$為長度為$i$的全排列的逆序對期望,有$dp[i]=dp[i-1]+$$\frac{i-1}{2}$,可以理解成在原$dp[i-1]$的基礎上,數值$i$對每個長度為$i-1$的排列產生$\sum_{t=1}^{i-1}t$個逆序對,共有$(i-1)!$個排列,所以期望為$\frac{(i-1)!*i*(i-1)}{(2*i!)}$$=\frac{i-1}{2}$,移項後使用累加法可以求出通項為$dp[i]=$$\frac{i*(i-1)}{4}$。

$2.$非$-1$之間對答案的貢獻。可以將出現概率看作$1$,所以貢獻就是逆序對數量,用樹狀數組求。

$3.$$-1$與非$-1$之間的貢獻。設共有$cnt$個$-1$,考慮每個$a[i]$$\neq$$-1$,設這個$a[i]$它前邊$-1$的數量為$nop$,它大的未填的數的數量為$high[a[i]]$,那麽$a[i]$對這部分答案的貢獻為$\frac{nop*high[a[i]]*(cnt-1)!}{cnt!}$$=$$\frac{nop*high[a[i]]}{cnt}$。比$a[i]$小的數與$a[i]$後邊的$-1$構成類似的關系。

代碼:

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <cassert>
#include <cstring>
#include <iostream>
#include <algorithm>

#define IOS    ios::sync_with_stdio(0),cin.tie(0);
#define DBG(x) cerr << #x << " = " << x << endl;	

#define PII pair<int,int>
#define FI  first
#define SE  second

using namespace std;

typedef long long LL;
typedef long double LD;
typedef unsigned long long ULL;

const int inf = 0x3f3f3f3f;
const int mod = 998244353;
const double eps = 1e-8;
const double pi  = acos(-1.0);

void file(){
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
}

namespace BakuretsuMahou{

	const int N = 2e5 + 5;
	const int inv2 = (mod + 1) / 2;

	int n, a[N], vis[N];
	int high[N], low[N];
	int pre[N], cnt;
	LL ans, fac[N];

	LL add(LL a, LL b){
		return (a+b)%mod;
	}

	LL mul(LL a, LL b){
		return (a*b)%mod;
	}

	struct BIT{

		int c[N];

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

		void update(int x, int y){
			while(x <= n){
				c[x] += y;
				x += lowbit(x);
			}
		}

		LL query(int x){
			LL res = 0;
			while(x >= 1){
				res += c[x];
				x -= lowbit(x);
			}
			return res;
		}
	}tree;

	LL qpow(LL a, LL b, LL p){
		LL res = 1;
		while(b){
			if(b&1)res = mul(res, a);
			a = mul(a, a);
			b >>= 1;
		}
		return res;
	}

	LL Fermat(LL a, LL p){
		return qpow(a, p - 2, p);
	}

	LL dp(LL x){
		return mul(mul(x, x - 1), Fermat(4, mod));
	}

	void init(){
		fac[0] = 1;
		for(int i = 1; i < N; i++){
			fac[i] = mul(fac[i - 1], i);
		}
	}

	void Explosion(){
		init();
		scanf("%d", &n);
		for(int i = 1; i <= n; i++){
			scanf("%d", &a[i]);
			if(a[i] != -1){
				vis[a[i]] = 1;
				ans = add(ans, i - 1 - cnt - tree.query(a[i]));
				tree.update(a[i], 1);
			}else cnt++, pre[i]++;
			pre[i] += pre[i - 1];
		}
		ans = add(ans, dp(cnt));
		LL inv = Fermat(cnt, mod);
		for(int i = 2; i <= n; i++)low[i] = low[i - 1] + (vis[i - 1] ^ 1);
		for(int i = n - 1; i >= 1; i--)high[i] = high[i + 1] + (vis[i + 1] ^ 1);
		for(int i = 1; i <= n; i++){
			if(a[i] != -1){
				LL nop = pre[i], nos = pre[n] - pre[i];
				ans = add(ans, mul(mul(nos, low[a[i]]), inv));
				ans = add(ans, mul(mul(nop, high[a[i]]), inv));
			}
		}
		printf("%I64d\n", ans);
	}
}

int main(){
	//IOS
	//file();
	BakuretsuMahou::Explosion();
	return 0;
}

Codeforces 1096F(dp + 樹狀數組)