sincerit 处女座和小姐姐(三)(数位dp)

链接: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

发布了118 篇原创文章 · 获赞 5 · 访问量 6834

猜你喜欢

转载自blog.csdn.net/sincerit/article/details/86661745