链接:https://ac.nowcoder.com/acm/contest/329/G
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
经过了选号和漫长的等待,处女座终于拿到了给小姐姐定制的手环,小姐姐看到以后直呼666!
处女座其实也挺喜欢6这个数字的,实际上他做手环的时候选取的k=6。所以他对于包含数码6的数字极其敏感。每次看到像4567这样的数字的时候他的心就像触电了一样,想起了小姐姐。
现在你要给处女座展示一系列数字,你想知道他的内心会激动多少次。对于同一个数字,他最多只会激动一次,即如果这个数是66666,他还是只会激动一次。
输入描述:
一行包括两个数字l,r,表示你给处女座展示的数字范围为[l,r]。
输出描述:
一行一个整数,表示处女座内心激动的次数。
示例1
输入
复制
10 20
输出
复制
1
现学现卖的数位dp(理解能力有限,见谅)
#include <stdio.h>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
ll dp[20][2]; // dp[len][0] 表示数字长度为len的数字且不含6个数字数
ll num[20]; // num是存储一个数字的每一位到这(个位十位百位。。。)
// 算法思想,另一种形式的暴力枚举(比传统的效率更高一些,是按照位数枚举的(百位十位个位由高到低枚举))
// 数位dp
// dfs(len, 0, 1) // 表示搜到的长为len的数字中不含6的数字个数
ll dfs(int len, bool judge, int limit) {
// len表示第几位数(个位十位还是百位)
// judge = 0表示不含6, judge=1表示含6
// limit 表示第len位数的更高一位是否为上界(刚开始时是1可以看作前导0是上界)
// 什么是上界 比如213 枚举百位时 当枚举的数是2时,不能再往上枚举了 2就是上界, 213==0213前导0
if (len == 0) return 1; // 枚举完了,且上一位数字不含6,找到一个数字不含6
else if (!limit && dp[len][judge]) { // 表示dp[len][judge]搜索过
return dp[len][judge];
}
ll cnt = 0;
ll up = limit ? num[len] : 9; // 如果没有前一个不是上界,后一位可以枚举到9
// 比如 213, 百位枚举到1时,个位和十位都可以枚举到9,但百位是2时,就不行
for (int i = 0; i <= up; i++) {
if (i == 6) continue; // 这里是不找含6的数字
cnt += dfs(len-1, i == 6, limit && i == up); // i==6可以改成 0
}
if (!limit)
dp[len][judge] = cnt;
return cnt;
}
ll init(ll x) {
int len = 0;
while (x) {
num[++len] = x % 10;
x /= 10;
}
return dfs(len, 0, 1); // 1表示最高为的前一位是上界
}
int main() {
ll l, r;
scanf("%lld %lld", &l, &r);
printf("%lld\n", (r - l + 1) - (init(r) - init(l-1))); // 前缀思想
return 0;
}
借鉴大佬的:
https://blog.csdn.net/jk211766/article/details/81474632
https://www.cnblogs.com/acalvin/p/3760082.html
https://www.cnblogs.com/zbtrs/p/6106783.html