题解:P11319 [NOISG2020 Qualification] Cryptography

康托展开

模版

给大家一个式子,这个式子就是康托展开的模版。

\(rank = 1 + \sum_{i=1}^{n} a_n \times (n-i)!\)

然后我们对这个排列 \(P\) 进行离散化,最后直接来个康托展开的模版就行了。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>


using namespace std;

const int maxm = 1000006;
const int mod = 1e9 + 7;
typedef long long ll;
ll fac[maxm], c[maxm], pos[maxm], n, ans = 1;
// 因为计算排名,所以 ans 初始为 1 
// c 为树状数组 

struct node {
	ll id, x;
}a[maxm];

bool cmp(node x, node y) {
	return x.x < y.x;
}

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

ll sum(ll x) { // 求和 
	ll ans = 0;
	while (x > 0) {
		ans += c[x] % mod;
		x -= lowbit(x);
	}
	return ans % mod;
}

void add(ll x, ll k) { // 增加 k  
	while (x <= n) {
		c[x] += k;
		x += lowbit(x);
	}
}

int main() {
	scanf("%lld", &n);
	for (int i = 1; i <= n; i++) 
		scanf("%lld", &a[i].x), a[i].id = i;
	sort(a + 1, a + n + 1, cmp);
	for (int i = 1; i <= n; i++)
		pos[a[i].id] = i; // 离散化,使数值减小并且更加清楚 
	fac[0] = 1; // fac 计算阶乘 
	for (int i = 1; i <= n; i++) {
		fac[i] = fac[i-1] * i % mod;
		fac[i] %= mod;
	}
	// 康托展开模版 
	for (int i = 1; i <= n; i++) add(i, 1);
	for (int i = 1; i <= n; i++) {
		ans += ((sum(pos[i]) - 1) * fac[n - i] % mod) % mod;
		add(pos[i], -1);
	}
	printf("%lld\n", ans % mod);
	return 0;
}
posted @ 2024-12-15 21:16  Panda_LYL  阅读(9)  评论(0)    收藏  举报