题目描述:
如果一个正整数每一个数位都是 互不相同 的,我们称它是 特殊整数 。
给你一个 正 整数 n
,请你返回区间 [1, n]
之间特殊整数的数目。
数据范围:
$1\le n \le 2 \times 10^9$
题解:
首先,所有位置都不能相同,这个就是状态,使用 $dp[step][s]$ 表示填了 $step$ 位,且状态为 $s$ 时的个数,状态就是使用了哪些数字,很容易想到需要状态压缩。而且只有 $10$ 个数字,状态压缩只需要 $2^{10}$ 的空间。
这个是需要记录 $isLead$ 的,因为前导零的 $0$ 是不计入使用过的数字的。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| auto optimize_cpp_stdio = []() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout.tie(nullptr); return 0; }(); class Solution { public: const static int maxn = 1e5 + 10; const static int maxm = 1e5 + 10; const int INF = 0x3f3f3f3f; string s; int len; int dp[10][1 << 10]; int dfs(int step, int mask, bool isLimit, bool isLead) { if (step == len) return !isLead; if (!isLimit && !isLead && dp[step][mask] != -1) return dp[step][mask]; int ans = 0; if (isLead) ans += dfs(step + 1, mask, false, true); int up = isLimit ? s[step] - '0' : 9; for (int i = isLead; i <= up; ++i) { if ((mask >> i) & 1) continue; ans += dfs(step + 1, mask | (1 << i), isLimit && i == up, false); } if (!isLimit && !isLead) dp[step][mask] = ans; return ans; } int countSpecialNumbers(int n) { s = to_string(n); len = s.length(); memset(dp, -1, sizeof(dp)); return dfs(0, 0, true, true); } };
|