题目描述
如果一个正整数每一个数位都是 互不相同 的,我们称它是 特殊整数 。
给你一个 正 整数 n
,请你返回区间 [1, n]
之间特殊整数的数目。
例如,$n = 20$ 输出:19 解释:1 到 20 之间所有整数除了 11 以外都是特殊整数。所以总共有 19 个特殊整数。
输入格式
第1行:1个整数$n$
输出格式
第1行:1个整数,表示满足条件的答案
样例
INPUT1
复制20
INPUT2
复制135
INPUT2
复制135
OUTPUT2
复制110
数据范围与提示
对于 100 的数据,1 <= n <= 2 * 1e9
题解
#include<bits/stdc++.h>
using namespace std;
const int N = 11;
int memo[N][1 << 10];
int n, m;
string s;
int dfs(int i, int msk, bool lim, bool ok){
if(i == m) return ok; //vis 为 true 表示得到了合法数字
if(! lim && ok && memo[i][msk] != -1)
return memo[i][msk];
int ret = 0;
if(!ok) //之前是前导 0,当前位也是填 0
ret = dfs(i + 1, msk, false, false);
int up = lim ? s[i] - '0' : 9; //如果前面填的数字都和 n 的一样,那么这一位至多填数字 s[i]
for(int j = 1 - ok; j <= up; j++) //前面没填数字,则必须从1开始
if( (msk >> j & 1) == 0) //j 未出现过
ret += dfs(i + 1, msk | (1 << j), lim && (j == up), true);
if(!lim && ok)
memo[i][msk] = ret;
return ret;
}
int main(){
cin >> n;
s = to_string(n);
m = s.size();
memset(memo, -1, sizeof memo);
int ans = dfs(0, 0, true, false); //首位受限制
cout << ans << '\n';
return 0;
}