统计特殊整数

Link CQBZOJ

题目描述

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值