hdu 3555 Bomb

问$[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 }
hdu 3555 Bomb

posted @ 2018-09-05 17:00  KingSann  阅读(123)  评论(0编辑  收藏  举报