问$[1,n]$有多少整数的十进制表示下存在$49$这个子串
$1 \le n \le 2^{63}-1$
学了一下正确的数位$dp$科技
首先需要把$n$按照十进制拆解了,比如说$153$,把它拆解之后就是$[3,5,1]$(从左到右对应着从低位往高位),把这个存到一个数组里,就叫它$dig$数组,下标是从$1$开始的
之后需要一个$dfs(pos,state,bounded)$函数,表示处理长度为$pos$的串、状态为$state$、是否顶到上界的答案
先说明一下什么叫做顶到上界,这里假设一下$pos=5$,$n=1647323$
如果$bounded=0$的话,相当于询问$0 \sim 99999$中有多少个满足条件的数
如果$bounded \not= 0$的话,顶到上界的意思就是$n$的前缀都必须选上,既$0 \sim 164abcd$的答案,其中$abcd$不能超过$7323$,把这个$bounded$属性下传即可
之后只需要枚举当前位置填多少就行了……


1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 ll f[30][4], n, dig[30]; 6 7 int nxt(int st, int i) { 8 if(st == 2) return 2; 9 else if(st == 0) return i == 4; 10 else return i == 9 ? 2 : i == 4; 11 } 12 13 ll dfs(int pos, int st, int bd) { 14 if(pos == 0) { 15 return st == 2; 16 } else if(!bd && f[pos][st] != -1) { 17 return f[pos][st]; 18 } else { 19 int top = bd ? dig[pos] : 9; 20 ll sum = 0; 21 for(int i = 0 ; i <= top ; ++ i) { 22 sum += dfs(pos - 1, nxt(st, i), bd && i == top); 23 } 24 if(!bd) f[pos][st] = sum; 25 return sum; 26 } 27 } 28 29 void sol() { 30 memset(f, -1, sizeof f); 31 scanf("%lld", &n); 32 int pos = 0; while(n) dig[++ pos] = n % 10, n /= 10; 33 printf("%lld\n", dfs(pos, 0, 1)); 34 } 35 36 int main() { 37 int T; scanf("%d", &T); 38 while(T -- ) sol(); 39 }