xbz分组题B 吉利数字 数位dp入门

B吉利数字
时限:1s

【题目描述】
算卦大湿biboyouyun最近得出一个神奇的结论,如果一个数字,它的各个数位相加能够被10整除,则称它为吉利数。现在叫你计算某个区间内有多少个吉利数字。

【输入】
第一行为样例个数N。接下来N行,每一行代表一个输入样例,每个输入样例有2个数,分别代表某个区间的起点a和终点b。
注意所求区间为[a,b],1<=a<=b<=10^9

【输出】
N行。对于第x个输入样例,在第x行输入该样例所对应的结果。

【输入样例】
2
1 10
1 20

【输出样例】
0
1

【Hint】1-10之内无幸运数,1-20内只有19 这1个幸运数
------------------------------------------------------------------------------------

数位dp入门题。

一开始参考了数位dp入门ppt的非递归写法,先打个表再计算,结果YY了半天还是错了T^T

这里有个用dfs写法写数位dp的模板:

http://www.cnblogs.com/jffifa/archive/2012/08/17/2644847.html

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 int dp[100][100];
 4 int dig[100];
 5
 6 int dfs(int i,int s,bool e)
 7 {
 8     if (!i) return (s==0?1:0);
 9     if ((!e)&&(dp[i][s]!=-1))    return dp[i][s];
10     int res=0;
11     int u=e?dig[i]:9;
12     for (int q=0;q<=u;q++)
13         res+=dfs(i-1,(s+q)%10,e&&q==u);
14     if (!e)    dp[i][s]=res;
15     return res;
16 }
17
18 int f(int n)
19 {
20     int len = 0;
21     while(n)
22     {
23         dig[++len] = n % 10;
24         n /= 10;
25     }
26     return dfs(len,0,true);
27 }
28
29 int main()
30 {
31     int a,b,T;
32     memset(dp,-1,sizeof(dp));
33     scanf("%d",&T);
34     while (T--)
35     {
36         scanf("%d %d",&a,&b);
37         printf("%d\n",f(b)-f(a-1));
38     }
39     return 0;
40 }

核心部分:(来自neopenx大神,orz)

 1 int dfs(int len,int remain,bool fp)
 2 {
 3     if(!len) return remain==0?1:0;
 4     if(!fp&&dp[len][remain]!=-1)
 5         return dp[len][remain];
 6     int ret=0,fpmax=fp?digit[len]:9;
 7     for(int i=0;i<=fpmax;i++)
 8         ret+=dfs(len-1,(remain+i)%10,fp&&i==fpmax);
 9     if(!fp) dp[len][remain]=ret;
10     return ret;
11 }
12
13 int f(int n)
14 {
15     int len=0;
16     while(n)
17     {
18         digit[++len]=n%10;
19         n/=10;
20     }
21     return dfs(len,0,true);
22 }

len:表示当前扫描到的数的位数,从高位向地位扫描

remain:表示当前状态。如本题中表示从最高位到当前位各位数字和%10

fp:又叫first place,neopenx的大神的理解是第一次打表

该dfs函数的基本思想也是打个表记下来,边记边用

fpmax:当前最高位

扩展:hdu2089

http://blog.csdn.net/dgq8211/article/details/9296953

时间: 2024-10-19 19:33:23

xbz分组题B 吉利数字 数位dp入门的相关文章

数位DP入门题 hdu 2089 hdu 3555

hdu 2089 不要62 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089 题意:对于每次给出的一个区间,找出区间内多少个数字没有出现62和4. 思路: 数位DP入门题,对于dfs设置3个参数. 一个表示现在进行到第几位, 一个表示前一个标记状态,这里表示上一位是不是6. 一个表示是否现在是这位可以取到的最大的数字. 如果上一位是6,那么这位不可以取2.且当前位都不可以取4. 1 #include <bits/stdc++.h> 2 us

HDU 2089 不要62【数位DP入门题】

不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 56193    Accepted Submission(s): 21755 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可

HDU 2089 不要62 数位DP入门

Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众.不吉利的数字为所有含有4或62的号码.例如:62315 73418 88914都属于不吉利号码.但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列.你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多

数位DP入门:bzoj1833: [ZJOI2010]count 数字计数

膜拜了一下蔡大神....然后突然想起来一些东西然后就填了一个半年多前的坑= = 人生第一道自己写的数位DP...好吧以前是看题解然后也不知道为什么就过了的>_< 数位DP介绍: http://wenku.baidu.com/link?url=9OS5Ybpw5wx00ahrH8ED2oyIlR1uWwrxT8N4pEg27GgBt2T2hLe4sd_h1rmpY7P0HmeHIEDw9h6_K98dPhhjoMhD2TpKcS8w1X8cC_dkPp_ 接下来是题目地址: http://www

SCUT - 289 - 小O的数字 - 数位dp

https://scut.online/p/289 一个水到飞起的模板数位dp. #include<bits/stdc++.h> using namespace std; typedef long long ll; bool notp[2000]; const int MAXS1=200; const int MAXS2=2000; int a[20]; ll dp[20][MAXS1][MAXS2]; ll dfs(int pos,int s1,int s2,bool lead,bool l

HDU 2089 数位dp入门

开始学习数位dp...一道昨天看过代码思想的题今天打了近两个小时..最后还是看了别人的代码找bug...(丢丢) 传说院赛要取消 ? ... 这么菜不出去丢人也好吧~ #include<stdio.h> #include<string.h> #include<algorithm> #include<map> #include<math.h> #include<queue> using namespace std; int n,m; /

HDU 2089 不要62(数位dp入门)

题意:统计区间 [a,b] 中不含 4 和 62 的数字有多少个. 题解:这是数位DP的入门题了,首先要理解数DP的原理,DP[i][j]:代表第i位的第j值,举个栗子:如4715   数位数是从右向左的,则第一位是5,第二位是1,第三位是7,第四位是4.所以如果要求0到4715,ans=dp[4][x]+dp[3][y]+dp[2][z]+dp[1][k] 0<=x<=4(但是4要去掉),0<=y<=9,0<=z<=9,0<=k<=9(还要注意判断,把其中

51nod 1009 数位dp入门

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1009 1009 数字1的数量 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题 收藏 关注 给定一个十进制正整数N,写下从1开始,到N的所有正数,计算出其中出现所有1的个数. 例如:n = 12,包含了5个1.1,10,12共包含3个1,11包含2个1,总共5个1. Input 输入N(1 <= N <= 10^9) Output 输出

HDU-2089不要62-暴力或数位DP入门

不要62 题意:给定区间,求在这个区间中有多少个数字,不包含4且不包含62: 这道题作为数位DP的入门题: 暴力也是可以过 #include<cstdio> #include <iostream> #include <cstring> #include <string> #include <algorithm> using namespace std; const int maxn =1e6+7; int a[maxn]; bool check(