You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

94 lines
4.7 KiB

2 years ago
#include <bits/stdc++.h>
using namespace std;
const int N = 32; // 输入的数据范围2^31-1,也就是整数上界。2进制是最小的进制32也够了
int a[N], al;
int f[N][N];
/*
f[i][j]:
i46934,
jsti,
 f[3][4]:341f[3][4]
*/
/*
:
u : 421,34
st :,1
lead :
op :
*/
int dfs(int u, int st, bool lead, bool op) {
// 递归边界既然是按位枚举最低位是1那么u==0说明这个数我枚举完了
if (u == 0) return 1; /*这里一般返回1表示你枚举的这个数是合法的
u
1 */
// 第二个就是记忆化(在此前可能不同题目还能有一些剪枝)
// 不贴上界,不需要考虑前导零,以前计算过,这样的东西才能拿来即用
if (!op && !lead && ~f[u][st]) return f[u][st];
/*常规写法都是在没有限制的条件记忆化,这里与下面记录状态是对应,具体为什么是有条件的记忆化后面会讲*/
int up = op ? a[u] : 9; // 根据limit判断枚举的上界up;这个的例子前面用213讲过了
int ans = 0;
// 开始计数
for (int i = 0; i <= up; i++) { // 枚举把不同情况的个数加到ans就可以了
// 这里可以加一些减枝之类的代码
/*
==  &&  i == a[pos] op &&
pos-1:dfspos-1
lead && i == 0:
0i ==0 ,
0i>0,
0
op && i == a[u] :
op=true,i
op=false,
*/
st = st + i; // 这句话是灵活的因题而异一般是描述传递状态的变更比如选择当前数位的数字1就多了一个1需要+1等等
ans += dfs(u - 1, st, lead && i == 0, op && i == a[u]);
/*这里还算比较灵活,不过做几个题就觉得这里也是套路了
i
sti
62,stpre,
62
*/
}
// 计算完,记录状态
if (!op && !lead) f[u][st] = ans;
/*这里对应上面的记忆化在一定条件下时记录保证一致性当然如果约束条件不需要考虑lead这里就是lead就完全不用考虑了*/
return ans;
}
// 因为用前缀和思想所以要计算r和l-1两次封成一个calc函数。
int calc(int x) {
al = 0; // 注意清零al清零即可a不用memset清零
// 把数位都分解出来
while (x) a[++al] = x % 10, x /= 10; // 个人喜欢编号为[1,al]
return dfs(al, 0, true, true); // 从最高位开始枚举,刚开始最高位都是有限制并且有前导零的显然比最高位还要高的一位视为0嘛
}
int main() {
int l, r;
while (cin >> l >> r) {
// 初始化dp数组为-1
memset(f, -1, sizeof f);
printf("%lld\n", calc(r) - calc(l - 1));
}
return 0;
}