hdu 4722 Good Numbers( 数位dp入门)

本文介绍了一种计算给定区间内好数数量的方法。好数是指其各位数字之和能被10整除的数。通过使用数位DP和记忆化搜索技巧,解决了这一问题并提供了代码实现。

Good Numbers

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3467    Accepted Submission(s): 1099


Problem Description
If we sum up every digit of a number and the result can be exactly divided by 10, we say this number is a good number.
You are required to count the number of good numbers in the range from A to B, inclusive.
 

 

Input
The first line has a number T (T <= 10000) , indicating the number of test cases.
Each test case comes with a single line with two numbers A and B (0 <= A <= B <= 10 18).
 

 

Output
For test case X, output "Case #X: " first, then output the number of good numbers in a single line.
 

 

Sample Input
2
1 10
1 20
 
 

 

Sample Output
Case #1: 0 Case #2: 1
Hint
The answer maybe very large, we recommend you to use long long instead of int.
 

 

Source

 

题意:给定区间A到B(用 long long),求其间好数有多少,好数是指每位数字加起来的和对10取余结果是0。

 

当时不明白何为学长讲的边界,另外数位dp还有递推版,但是递推太容易出错,还是记忆化搜索比较容易理解~

 

 1 #include<iostream>
 2 #include<vector>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <cstdlib>
 6 #include <math.h>
 7 #include<algorithm>
 8 #define ll long long
 9 #define eps 1e-8
10 using namespace std;
11 ll dp[20][20]; // 统计第几位数余数为几有多少个
12 int num[20]; //存放每位数字
13 ll dfs(int site,int mod,int f)
14 {
15     if(site == 0)
16         return mod == 0 ? 1:0; // 递归结束条件,并判断最后一位时是否余数为0
17     if(!f && dp[site][mod] != -1) //记忆化搜索
18         return dp[site][mod];
19     int len = f == 1?num[site]:9; //若当前位为边界則当前位只枚举0-当前,否则枚举0-9
20     ll ans = 0;
21     for(int i = 0; i <= len; i++)
22         ans += dfs(site-1,(mod+i)%10,f && i == len);//f判断是否为边界
23     if(!f)
24         dp[site][mod] = ans; //边界不能存,因为之前计算的是不看边界的,便于以后用到,如果存了,就是一个错误的统计
25     return ans;
26 }
27 ll solve(ll digit)
28 {
29     memset(num,0,sizeof(num));
30     int l = 0;
31     while(digit)
32     {
33         num[++l] = digit%10;
34         digit /= 10;
35     }
36     return dfs(l,0,1);
37 }
38 int main(void)
39 {
40     int t,cnt = 1;
41     ll a,b;
42     memset(dp,-1,sizeof(dp));
43     scanf("%d",&t);
44     while(t--)
45     {
46         scanf("%lld %lld",&a,&b);
47         printf("Case #%d: %lld\n",cnt++,solve(b)-solve(a-1));
48     }
49     return 0;
50 }

 

转载于:https://www.cnblogs.com/henserlinda/p/4717710.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值