• 【算法•日更•第十三期】信息奥赛一本通1589:不要 62题解


      废话不多说,直接上题:


    1589:不要 62


    时间限制: 1000 ms         内存限制: 524288 KB
    提交数: 105     通过数: 67 

    【题目描述】

    原题来自:HDU 2089

    杭州人称那些傻乎乎粘嗒嗒的人为 62(音:laoer)。

    杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。

    不吉利的数字为所有含有 4 或 62 的号码。例如:62315,73418,8891462315,73418,88914 都属于不吉利号码。但是,61152 虽然含有 6 和 2,但不是 62 连号,所以不属于不吉利数字之列。

    你的任务是,对于每次给出的一个牌照区间号,推断出交管局今后又要实际上给多少辆新的士车上牌照了。

    【输入】

    输入的都是整数对 n,m,如果遇到都是 0 的整数对,则输入结束。

    【输出】

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

    【输入样例】

    1 100
    0 0

    【输出样例】

    80

    【提示】

    数据范围与提示:

    对于全部数据,0<nm<107 。

    【来源】


      这道题乍一看挺简单,但是看一眼心态就崩了。107,而且还是多次输出,一看就是要预处理,像这种要预处理的而且和数位有关的,使我们会想到数位动态规划。

      小编最开始的想法很简单,f[i]表示0~i之间的合法个数,那么就有f[i]=f[i-1]+(i==合法);(伪代码),那么答案就是f[m]-f[n-1],似乎是区间动态规划的方法。但是时间太慢了,小编也觉得不太可能。

      这是小编想到的状态,实在想不到和数位有关的方法了。看了看大佬的博客才发现状态原来可以这样设计:用f[i][j]表示以j开头的i位数的合法个数。

      那么就很清晰了,就有f[i][j]=sum{f[i-1][k]},其中k!=4,j!=4,!(k==2&&j==6),举个栗子:比如说f[3][1]=f[2][0]+f[2][1]+f[2][2]+f[2][3]+f[2][5]+f[2][6]+f[2][7]+f[2][8]+f[2][9]。

       那么剩下的问题就是怎么处理区间[n,m],把它分为[0,n]和[0,m+1](知道你会说什么,这和后面的算法有关)

      先不说n和m,假设现在要统计0~71806291的区间,那么我们就可以遍历各个数位i,同时枚举各数位数字j,如果合法,那么就把答案加上f[i][j]就可以了,如果发生了这样的情况:题目中的数字不合法,那么就加上f[i][j]后退出循环,因为后面的都计过了。比如说6291,先到了6,加上5000个数的合法个数,到了2会加上2000个数的合法个数,然后退出循环,就会发现前6200的合法个数都加上了,而后面的就不加了,因为这是建立在6200的基础上的,一定不合法。

      好了,详见注释,代码如下:

     1 #include<iostream>
     2 using namespace std;
     3 int n,m,f[1000][1000];
     4 int calc(int x)//计算0~x区间内合法个数 
     5 {
     6     int s[1000]={0},cnt=0,ans=0;
     7     while(x)//分解数位 
     8     {
     9         s[++cnt]=x%10;
    10         x/=10;
    11     }
    12     for(int i=cnt;i>=1;i--)
    13     {
    14         for(int j=0;j<=s[i]-1;j++) //因为后面的数不能超过,所以只能到s[i]-1 
    15         if(!(j==4||(j==2&&s[i+1]==6))) ans+=f[i][j];//合法就加上 
    16         if(s[i]==4||(s[i]==2&&s[i+1]==6)) break;//数字中不合法就退出循环 
    17     }
    18     return ans;
    19 }
    20 int main()
    21 {
    22     f[0][0]=1;
    23     for(int i=1;i<=7;i++)//预处理 
    24     for(int j=0;j<=9;j++)
    25     for(int k=0;k<=9;k++)
    26     if(j!=4&&!(j==6&&k==2)) f[i][j]+=f[i-1][k];
    27     while(1)
    28     {
    29         cin>>n>>m;
    30         if(n==0&&m==0) break;
    31         cout<<calc(m+1)-calc(n)<<endl;
    32     }
    33     return 0;
    34 }
  • 相关阅读:
    day17_sql优化——AWR
    [笔记]《HTTP权威指南》- 媒体类型和字符集
    分析 webpack 打包后的代码
    跨站点请求伪造(CSRF)
    如何定制 fis3-jello
    [翻译]简单的实现一个Promise
    浏览器的 bfcache 特性
    Linux 下搭建 FTP 服务器
    better-scroll 源码分析
    [笔记]移动端的 viewport 和各种像素区分
  • 原文地址:https://www.cnblogs.com/TFLS-gzr/p/11194885.html
Copyright © 2020-2023  润新知