1. 程式人生 > 實用技巧 >康託展開

康託展開

康託展開

利用康託展開,可以求得全排列的序列號

康託展開有公式: \(ans=\sum_{i=1}^{n}{k \times (i-1)!} + 1\)

其中的 \(k\) 即為該點構成的逆序對的數量

code

#include<iostream>
#include<cstdio>
#include<math.h>
#include<cstring>
#include<queue>
#include<vector>
#include<bitset>
#include<map>
#include<algorithm>
#define ll long long

const ll mod=998244353;
const ll maxn=1000010;
ll n,ans;
ll a[maxn],tre[maxn],b[maxn],f[maxn];

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

inline void upd(ll x,ll w)
{
	while(x<=n)
	{
		tre[x]+=w;
		x+=lowbit(x);
	}
}

inline ll sum(ll x)
{
	ll sum=0;
	while(x)
	{
		sum+=tre[x];
		x-=lowbit(x);
	}
	return sum;
}

inline void pre()
{
	f[0]=1;
	
	for(int i=1;i<=n;i++)
	{
		f[i]=f[i-1]*i%mod;
	}
}

int main(void)
{
	scanf("%lld",&n);
	
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",a+i);
	}
	
	pre();

	for(int i=n;i>=1;i--)
	{
		(ans+=sum(a[i]-1)%mod*f[n-i]%mod)%=mod;
		upd(a[i],1);
	}
	
	printf("%lld\n",(ans+1)%mod);
	
	return 0;
}