这题写的真心有点纠结。首先确定需要多少位来容纳这个数,然后找到第一个要更新的位置,再逐位更新。
代码如下:
#include <cstdlib> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef long long int Int64; bool hash[20]; int digit[10], Most; Int64 s[10], f[20], N; void pre() { f[0] = s[0] = 1; for (int i = 1; i <= 16; ++i) { f[i] = f[i-1] * i; } for (int i = 1; i <= 8; ++i) { s[i] = f[16-Most+i] / f[16-Most]; } s[Most] -= s[Most-1]; } void update(int pos) { for (int i = 15; i >= 0; --i) { if (!hash[i]) { digit[pos] = i; hash[digit[pos]] = true; return; } } } void dfs(int pos, Int64 k, int start) // 需要开始调整的位置以及需要调整的指数 { int deep = (int)floor(1.0 * k / s[pos-1]), cnt = 0, left; if (deep) { hash[digit[pos]] = false; for (int i = start; i >= 0; --i) { if (!hash[i]) { ++cnt; } if (cnt == deep) { digit[pos] = i; hash[digit[pos]] = true; break; } } // 这一位我们就确定了下来 } left = k-deep*s[pos-1]; if (pos-1 > 0) { update(pos-1); dfs(pos-1, left, digit[pos-1]-1); } } void init() { pre(); memset(digit, 0, sizeof (digit)); memset(hash, 0, sizeof (hash)); for (int i = 16 - Most, j = 1; i <= 15; ++i, ++j) { hash[i] = true; // 声明出这些数是已占用的 digit[j] = i; } } int main() { while (scanf("%I64d", &N) == 1) { pre(); N -= 1; for (int i = 8; i >= 1; --i) { N -= 15 * f[15]/f[15-i+1]; if (N < 0) { N += 15 * f[15]/f[15-i+1]; Most = i; break; } } init(); for (int i = 1; i <= Most; ++i) { hash[digit[i]] = false; if (N - s[i] < 0) { dfs(i, N, digit[i]-1); break; } } for (int i = Most; i >= 1; --i) { if (digit[i] > 9) { printf("%c", digit[i]-10+'A'); } else { printf("%d", digit[i]); } } puts(""); } return 0; }