[康托展开+逆展开] 理解 和 代码总结

之前 听说过
现在做IDA* 八数码没有一坨优化过不去问题必须学的
这里写下笔记

首先洛谷 P1379
https://www.luogu.org/problem/P1379

我自己对[康托展开+逆展开] 代码总结
n^2 和 logn 我都写了 洛谷这个题强制要优化

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;
const int mod = 998244353;
int n, a[maxn], c[maxn], f[maxn];

void add(int x, int y) {
	for(; x <= n; x += (x & -x)) c[x] += y;
}

int sum(int x) {
	int res = 0;
	for(; x; x -= (x & -x)) res += c[x];
	return res;
}

int cantor(int *a, int n) {
	int x = 0;
	for (int i = 1; i <= n; ++i) {
		int tmp = 0;
		for (int j = i + 1; j <= n; ++j)
			if (a[j] < a[i])
				tmp++;
		x += f[n - i] * tmp;
	}
	return x ; // + 1 要不从零开始
}


void decantor(int n, int k, int *a) {
	int j, t, vst[8]= {0};
	--k;
	for (int i =  1; i <= n; i ++) {
		t = k / f[n - i];
		for (j = 1; j <= n; j ++){
			if (!vst[j]) {
				if (t == 0) break;
				-- t;
			}
		}
		a[i] = j;
		vst[j] = 1; 
		k %= f[n - i];
	}
	for(int i = 1; i <= n; i++) cout << a[i] << " " ; cout << endl;
}

int main() {
	cin >> n;
	f[0] = f[1] = 1;
	for(int i = 2; i <= n; i ++) f[i] = 1ll * f[i - 1] * i % mod;
	// n * n cantor 函数 
// for(int i = 1; i <= n; i ++) cin >> a[i], add(i, 1);
// ll ans = 0;
// cout << cantor(a, n) << endl;

// nlgn 树状数组优化 算法 
 
// for(int i = 1; i <= n; i ++) {
// ans = (ans + (1ll * (sum(a[i]) - 1) * f[n - i]) % mod) % mod;
// add(a[i], -1);
// }
// cout << ans + 1 << endl;

	// 逆展开 
// int k;
// cin >> k;
// decantor(n, k, a);

	return 0;
}

以下讲解取于教材



全部评论

相关推荐

挣K存W养DOG:他真的很中意你,为什么不回他
点赞 评论 收藏
分享
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务