hdu2089&&数圈圈(数位dp)
题目链接:
1,http://acm.hdu.edu.cn/showproblem.php?pid=2089
2,https://www.nowcoder.com/acm/contest/30/D
都是判断一个区间中的数字满足什么什么条件的有多少个,暴力的做法直接遍历,一个个数字的判断,然而数位dp很快,几乎在O(n*102),n是数字的位数,是非常快的
数位dp也就是数位之间的dp,如十位与个位,百位与十位。在测试数据组数很多的话,可以预处理,但一般不必要,直接记忆化搜索,要方便得多
数圈圈的AC代码:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<iostream>
4 #include<math.h>
5 using namespace std;
6 typedef long long ll;
7 ll dp[16][10]={0},pos[10],ning[20];
8
9 ll pow1(ll a,ll b)
10 { ll sum=1;
11
12 for(ll i=1;i<=b;i++)
13 sum*=a;
14 return sum;
15
16 }
17
18 ll dfs(int x) //x+1为位数,x为在数组中的位置
19 { ll sum=0;
20 if(x==-1) return dp[1][pos[x+1]];
21 for(int i=0;i<pos[x];i++)
22 {
23 sum+=dp[x+1][i];
24
25 }
26
27 sum+=dfs(x-1);
28 if(x>0) //需特判。。
29 {
30 if(pos[x]==0||pos[x]==4||pos[x]==6||pos[x]==9)
31 { ll y=0;
32 for(int i=x-1;i>=0;i--)
33 y=y*10+pos[i];
34
35 sum+=y+1;
36 }
37 if(pos[x]==8)
38 { ll y=0;
39 for(int i=x-1;i>=0;i--)
40 y=y*10+pos[i];
41
42 sum+=2*(y+1);
43
44 }
45 }
46
47 return sum;
48 }
49
50 ll solve(ll x)
51 { int tot=0;
52 if(x==0) return 0;
53 while(x)
54 {
55 pos[tot++]=x%10;
56 x=x/10;
57 }
58
59 return dfs(tot-1)-ning[tot]; //减去前导0的影响
60 }
61
62 int main()
63 { dp[1][0]=1,dp[1][4]=1,dp[1][6]=1,dp[1][8]=2,dp[1][9]=1; //预处理
64 ning[1]=1;
65 for(int i=2;i<20;i++)
66 ning[i]=ning[i-1]*10+1;
67 for(ll i=2;i<16;i++)
68 { for(int j=0;j<10;j++)
69 {
70 if(j==0||j==4||j==6||j==9)
71 dp[i][j]=pow1(10,i-1);
72 if(j==8) dp[i][j]=2*pow1(10,i-1);
73
74 for(int k=0;k<10;k++)
75 {
76 dp[i][j]+=dp[i-1][k];
77 }
78 }
79
80 }
81 int T;
82 scanf("%d",&T);
83 ll l,r;
84 while(T--)
85 { scanf("%lld%lld",&l,&r);
86
87 printf("%lld\n",solve(r)-solve(l-1));
88 }
89
90
91 return 0;
92 }
当时做了预处理,现在觉得还是直接记忆化搜索更方便,不用麻烦地特判处于上界的情况(如666,6就是每位的上界)