题解
问在[1, x]
之间的(所有数字) 的某类性质, 这是数位DP的问题;
按照数位DP的规定, Prefix( r)
表示: 在[0 - r]
之间的所有数字
所以, 将其转换为: Prefix( x) - Prefix( 1 - 1)
,
数位DP会将[0 - r]
的所有数字, 划分为3大类: 以r = 2345
(1, 第一类: 非对齐数字, 为所有< 1000
的数, 即[0 - 999]
这些)
(2, 第二类: 对齐数字, 为所有[1000, 2344]
这些数, 可以发现, 这些数字的长度是相同的)
(3, 第三类: r = 2345
)
一般, 优先考虑, (第二类数字) 是否有解; … 因为, 有时第一类数字的问题, 可以用与 (第二类数字) 相同的方法来解决
具体的, 第二类数字, 还会继续划分成:
([1000, 1999]
)
([2000, 2099]
[2100, 2199]
[2200, 2299]
)
([2300, 2309]
[2310, 2319]
[2320, 2329]
[2330, 2339]
)
([2340, 2340]
[2341, 2341]
[2342, 2342]
[2343, 2343]
[2344, 2345]
)
… 具体规则可以回顾(数位DP)知识.
我们称, 上面这13
个区间, 我们对(第二类数字)的处理过程, 就是 对这13个区间的处理; 即, 一个区间, 是我们最小的处理单元;
这每个区间, 他们都是可以表示为: abcd
, 且某个前缀是固定的
后缀是0-9的任意
比如, 对于区间[2100, 2199]
, 他为 (固定前缀为21
, 后缀任意), 所有区间都是这样的形式
因此, Aligned( vector< int> pre, int k)
函数, 就是针对每个区间, 求解该区间的答案;
… pre
为固定前缀(没有前导零), k
为后缀长度. 该区间有10^k
个数; [2100, 2199]
对应为Aligned( {2, 1}, 2)
那么, 比如对于[abc] [000 - 999]
区间, 他的答案是多少呢?
(1, 如果abc
是非法的 即, 存在两位相同
, 则, 整个区间全为非法的; ans为0)
(2, 否则, abc
互不相同, 则后缀有: [10-3种选择, 10-4种选择, 10-5种选择]
, 即ans = 7 * 6 * 5
, 因为所有位都不同, 就类似于(排列问题).
至此, (第二类数字) 我们已解决;
看第一类数字: [0, 999]
, 他一般有两种处理方法:
(1, 尝试用Aligned (即第二类数字的处理方法)
来解决, 通过将(第一类数字) 添加前导零, 使得 (第一类数字 与 第二类数字 ) 具有相同长度
… 即, 将[0, 999]
变成 [0000, 0999]
, 即Aligned( {0}, 3)
的答案 是否等于 [0, 999]
的答案呢?
… 答案是否定的! 0001
在 Aligned
里 会按照非法的来处理, 而0001
他在[0, 999]
里对应为1
他是合法的!!!
… 因此, 不可以添加前导零;
(2, 拆分集合; 将[0, 999]
继续划分为: ([0, 0]
[1, 9]
[10, 99]
, [100, 999]
)
… 这样划分的依据在于: (每个区间, 都是等长的)
… 每个区间的长度为: 1, 9, 90, 900, ...
… 除了第一个区间[0, 0]
, 其他区间 都是: [1 后面全是0, 9 后面全是9]
的形式;
… 对于每个区间, 继续进行划分: 比如[100, 999]
, 划分为: [100, 199]
[200, 299]
[300, 399]
…, [900, 999]
(共9个)
… 这样做的好处是: 对于每个小区间[200, 299]
, 他符合Aligned
的形式, 直接调用Aligned( {2}, 2)
即可
… … 而这里, 其实对于[1000, 9999]
, 也可以自己直接算: [9种, 9种, 8, 7, ..]
, ans = 9 * 9 * 8 * 7 ...
(注意, 第一位是[1-9]
, 其他位都是[0-9]
)
更新
题目要求的 (特殊数 所有位不同
), 那么, 数位DP 是选择计算(特殊数) 还是计算(非特殊数)呢?
… 这要看 [a b c] [000 - 999]
, 谁能在线性时间 处理这个集合的答案;
… 这里的(非特殊数), 并不是连续的
, 比如: 12341
是(非特殊数), 它是跳跃的; 这不是DP能处理的
… 而(特殊数), 每个位 都不同, 联系到(排列数)
注意点
- 这是一个非DP的数位DP, 不需要
Build_dp
记忆化; 直接暴力即可
代码
bool Is_valid(