HDU 2089-不要62(dp?暴力?方法是真的多)

原创 2018年04月16日 12:35:24

不要62

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 52666    Accepted Submission(s): 20065


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

Input
输入的都是整数对n、m(0<n≤m<1000000),如果遇到都是0的整数对,则输入结束。
 

Output
对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。
 

Sample Input
1 1000 0
 

Sample Output
80
 

Author
qianneng
 

Source


解题思路:本题给的数据范围是真的小,直接打表暴力即可水过,但本鶸鹡还是WA了好几发,忘了要离线解决问题,忘了前缀和为sum[b] - sum[a-1](而本鶸鹡写成了sum[b] - sum[a],真的,菜是原罪),最后还有一个更高深的解法,那就是数位dp,这个算法还是需要理解才能掌握的,接下来就直接上代码吧。


暴力1:数字打表(46ms)
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>

using namespace std;

int s[1000010];

int main()
{
    int a, b, num[10], sum;
    sum = 0;
    s[0] = 1;
    for(int i = 1; i <= 1000000; i ++) {
        if(i%10 == 4 || i/10%10 == 4 || i/100%10 == 4 || i/1000%10 == 4 || i/10000%10 == 4 || i/100000%10 == 4) {
            s[i] = s[i-1];continue;
        }
        if(i%100 == 62 || i/10%100 == 62 || i/100%100 == 62 || i/1000%100 == 62 || i/10000%100 == 62) {
            s[i] = s[i-1];continue;
        }
        s[i] = s[i-1]+1;
    }
    while(~scanf("%d%d", &a, &b)) {
        if(a == 0 || b == 0) break;
        printf("%d\n", s[b] - s[a]);
    }
    return 0;
}

暴力二:字符串转换打表(93ms)
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<stdlib.h>

using namespace std;

int sum[1000010], a, b;
char str[1000010];

int main()
{
    sum[0] = 1;
    for(int i = 1; i <= 1000000; i++) {
        itoa(i, str, 10); //把i转化为10进制的数再转化为字符串
        if(strstr(str, "4") == NULL && strstr(str, "62") == NULL) { //判断是否为子串
            sum[i] = sum[i-1] + 1;
            continue;
        }
        sum[i] = sum[i-1];
    }
    while(~scanf("%d%d", &a, &b)) {
        if(a == 0 || b == 0) break;
        printf("%d\n", sum[b] - sum[a-1]);
    }
    return 0;
}
我感觉 isoa函数 和 strstr函数 的使用非常巧妙!
isoa函数的介绍 (点击可查看,与sprintf函数作用差不多,但是有进制转化的功能)
strstr函数的介绍 (比较两个字符串是否有字串关系)

dp大法:数位dp法(0ms,在线解决,对于数据非常大的同样适用)
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<stdlib.h>

using namespace std;

int num[10], a, b, k;
int dp[10][2];

int dfs(int len, bool is6, bool limet)
{
    if(len == 0)
        return 1;
    if(!limet && dp[len][is6]) {
        return dp[len][is6];
    }
    int cnt = 0;
    int maxx = (limet ? num[len] : 9);
    for(int i = 0; i <= maxx;  i++) {
        if((i == 2 && is6) || i == 4) //条件判断
            continue;
        if(i == 6)
            cnt += dfs(len - 1, true, limet && i == maxx);
        else cnt += dfs(len - 1, false, limet && i == maxx);
    }
    return limet ? cnt : dp[len][is6] = cnt;
}

int solve(int n)
{
    memset(num, 0, sizeof(num));
    memset(dp, 0, sizeof(dp));
    k = 0;
    while(n > 0) {
        num[++ k]  = n%10; //使用k ++时注意dfs中的k要-1,并且初始化为1
        n /= 10;
    }
    dfs(k, false, true);
}

int main()
{
    while(~scanf("%d %d", &a, &b)) {
        if(a == 0 || b == 0) break;
        printf("%d\n", solve(b) - solve(a-1));
    }
    return 0;
}


HDU 2089 不要62(数位dp/暴力打表)

解题思路: 这题第一次做的时候,因为数据范围小,只有10^6,所以果断选择了暴力打表。在够表的时候,一开始少了a[i/10]==1这个条件,算出来的值总是多,, 然后加上后,扫一遍就过。 先看看...
  • wikioi_bai
  • wikioi_bai
  • 2015-02-20 11:51:04
  • 451

HDU 2089 不要62(数位DP,三种姿势)

HDU 2089 不要62(数位DP,三种姿势) ACM 题目地址:HDU 2089 题意:  中文题意,不解释。 分析: 100w的数据,暴力打表能过先初始化dp数组...
  • hcbbt
  • hcbbt
  • 2014-07-26 16:00:55
  • 7611

HDU 2089-不要62(数位DP)

不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub...
  • MIKASA3
  • MIKASA3
  • 2016-05-29 10:02:26
  • 630

数位DP入门+hdu 不要62

数位DP入门 数位DP其实是很灵活的,所以一定不要奢求一篇文章就会遍所有数位DP的题,这一篇只能是讲清楚一种情况,其他情况遇到再总结,在不断总结中慢慢体会这个思想,以后说不定就能达到一看到题目就能...
  • l2533636371
  • l2533636371
  • 2017-04-22 19:31:20
  • 560

HDOJ 2089-不要62

Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样...
  • sb_Ihateyou
  • sb_Ihateyou
  • 2016-11-30 14:00:22
  • 2153

HDU2089 不要62(数位DP入门经典题目)

昨天做了一道很奇怪的数字题,不知道怎么做,今天才知道是数位DP ……我来学习学习。 传送门 大意:给定区间[n,m][n,m],求在n到m中没有“62“或“4“的数的个数。如62315包含62,8...
  • geng4512
  • geng4512
  • 2015-08-24 20:48:09
  • 1583

HDU 2089 不要62(数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089题解:开一个dp数组,设i代表当前数字的长度,dp[i][0]表示不含4和62的数字, dp[i]...
  • Infinity_Izayoi
  • Infinity_Izayoi
  • 2016-07-20 21:50:37
  • 289

HDU 2089 不要62(数位dp&记忆化搜索)

题目链接:[kuangbin带你飞]专题十五 数位DP C - 不要62题意 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好...
  • to_be_better
  • to_be_better
  • 2016-02-14 00:04:25
  • 1574

【数位DP】 hdu2089 不要62

不要62 题目:http://acm.hdu.edu.cn/showproblem.php?pid=2089 题意:问在n,m之间不含4和62序列(4和62为不吉利数)的数字有多少个。 题解:把...
  • ACM_Ted
  • ACM_Ted
  • 2012-08-22 15:13:57
  • 4048

【杭电】2089 不要62【打表】

http://acm.split.hdu.edu.cn/showproblem.php?pid=2089 #include #include int luck(int x) { ...
  • Alternative_19
  • Alternative_19
  • 2016-10-27 17:49:05
  • 682
收藏助手
不良信息举报
您举报文章:HDU 2089-不要62(dp?暴力?方法是真的多)
举报原因:
原因补充:

(最多只允许输入30个字)