0%

2376. 统计特殊整数

2376.统计特殊整数

题目描述:

如果一个正整数每一个数位都是 互不相同 的,我们称它是 特殊整数

给你一个 整数 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);
}
};