- 题意:给你一个区间,求这个区间内所有满足不含数字2,不含连续数字62的数字的个数。(本题核心思想见代码注解)
- 题并非水,然而大部分人还是水过的,对1到10,000,000内数字转化为字符串打表处理即可水过。然而做这个题主要是为了掌握数位DP。
数位DP常见知识点:
- 求区间[l, r]之间的数常常转化为求区间[0 ,r] - [0, l]之间的数,因为l,r上界下界并不好做。
- 数位DP的核心就是无后效性导致的减少计算量,体现在这个题中就是,一个j开头的i位数(定义为
(i,j)
)只与
(i−1,k)
有关。
本题代码:
#include <set>
#include <map>
#include <cmath>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long int LL;
const int M = 100009,INF = 0x3fffffff;
int f[8][10];
int doit(int x) {
int ans = 0;
char d[8], digital[8];;
sprintf(d, "%d", x);
int len = strlen(d);
for (int i = len; i >= 1; i--) {
digital[i] = d[len - i];
}
digital[len + 1] = '\0';
for (int i = len; i >= 1; i--) {
for (int j = 0; j < digital[i] - '0'; j++) {
if(j != 4 && !(j == 2 && digital[i + 1] == '6')) ans += f[i][j];
}
if (digital[i] == '4' || (digital[i] == '2' && digital[i + 1] == '6')) break;
}
return ans;
}
int main(void) {
int n, m;
memset(f, 0, sizeof(f));
f[0][0] = 1;
for (int i = 1; i <= 7; i++) {
for (int j = 0; j <= 9; j++) {
for (int k = 0; k <= 9; k++) {
if(j != 4 && !(j == 6 && k == 2)) f[i][j] += f[i - 1][k];
}
}
}
while(cin >> n >> m && (n || m)) {
cout << doit(m + 1) - doit(n) << endl;
}
return 0;
}