宽搜总结

康托展开和康托展开的逆运算

相当于排列的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;
}
原文地址:https://www.cnblogs.com/sugewud/p/9933511.html