康托展开和康托展开的逆运算
相当于排列的hash
记住对于每一位,求比较小且没出现过的数有多少个,数的个数乘上阶乘就好了
#include<bits/stdc++.h> #define REP(i, a, b) for(register int i = (a); i < (b); i++) #define _for(i, a, b) for(register int i = (a); i <= (b); i++) using namespace std; typedef long long ll; const int MAXN = 20; ll p[MAXN]; int a[MAXN], vis[MAXN], n; ll kangtuo() { memset(vis, 0, sizeof(vis)); ll res = 0; REP(i, 1, n) { int cnt = 0; REP(j, 1, a[i]) if(!vis[j]) cnt++; res += cnt * p[n-i]; vis[a[i]] = 1; } return res + 1; //注意最后加一 } void print(ll sum) { sum--; //注意开始-1 memset(vis, 0, sizeof(vis)); _for(i, 1, n) { ll k = sum / p[n-i]; sum -= k * p[n-i]; int j = 1; //初始化为1 for(; j <= n; j++) //注意是小于等于n,不是9 if(!vis[j]) ///i和j不要搞混了 { if(!k) break; k--; } a[i] = j; vis[j] = 1; } _for(i, 1, n) printf("%d ", a[i]); puts(""); } int main() { p[0] = 1; _for(i, 1, 15) p[i] = p[i-1] * i; scanf("%d", &n); _for(i, 1, n) scanf("%d", &a[i]); printf("%lld ", kangtuo()); ll sum; scanf("%lld", &sum); print(sum); return 0; }