zoukankan      html  css  js  c++  java
  • 计数器

    Problem description

    一本书的页数为N,页码从1开始编起,请你求出全部页码中,用了多少个0,1,2,…,9。其中一个页码不含多余的0,如n=1234时第5页不是0005,只是5。

    Input format 

    一个正整数N(N<=10^9),表示总的页码。

    Output format

    共十行,第K行表示数字K-1的个数。

    Algorithm design

    模拟TLE/记忆化搜索AC

    Problem analysis

    模拟TLE

    先敲一下暴力,方便对拍

    从1枚举到n,每次将该数各位切分后加入答案、

    O(nlog10n)

    隐约觉得在切分的时候可以有些许优化把log10n提高一下

    但不用想了复杂度里有n本身肯定过不了

    记忆化搜索AC

    由计数问题得到的经验:对于较大整数状态转移不是去头就是去尾

    一开始想着去头,发现0不能做数头的问题约束了这个算法

    所以采取去尾状态转移法,去掉尾之后如果num成了0直接退出

    那么怎么状态转移呢?

    不难发现,对于一个数如234而言

    可以拆分为尾是0~9的数,又分为两大类:

    1.对于尾是0~4 那么十位数就可以从1枚到23

    2.对于尾是5~9 那么十位数就可以从1枚到22

    之后以此类推,直到1位数无法拆分

    既然如此就可以看出动态转移的基本模型了

    但是,在确定尾并不是被真正“去”掉了,而只是在确定之后不参与枚举

    那么答案数列里还要考虑枚举个数个尾

    至于枚举个数可以很容易的写出来,num%10(-1)

    想到这里还是简单递归,顶多比模拟多10分

    再看有许多低位数字被反复的使用,自然联想出记忆化思想

    因为要记忆化,图方便就对于0~9依次搜索

    这样记忆化只用开一维数组,且可以直接复制

    至于记忆化的范围,我觉得其实把常用的2,3位数记忆化就行了

    但在编程中要有“得寸进寸”的思想,在确保不会爆空间的情况下尽可能记得多

    所以我对于记忆化开了10^7..

    这样就很容易过了

    Source code

    记忆化搜索

     1 #include <bits/stdc++.h>
     2 #define lim 10000000
     3 
     4 using namespace std;
     5 
     6 int n,ans[10],opt[10000001];
     7 //opt[i]表示数字1~i可拆分出的某个数字个数
     8 
     9 void input()
    10 {
    11     freopen("test.in","r",stdin);
    12     freopen("test.out","w",stdout);
    13     cin>>n;
    14     return ;
    15 }
    16 
    17 int search(int tar,int num)
    18 {
    19     if(num<1)
    20         return 0;
    21 //如果要拆分的数小于1,则拆分无意义
    22     if(num<=lim&&opt[num])
    23         return opt[num];
    24 //如果可以记忆并被记忆过,则直接返回
    25     int re=0;
    26     if(tar&&tar<=num%10)
    27         re=num/10+1;
    28 //如果不为零,并且寻找的数不大于个位数,就可以考虑前面是0~num/10
    29     else 
    30         re=num/10;
    31 //如果为零,就不用考虑前面为0,如果大于个位数,就不用考虑num/10
    32     re+=(num%10+1)*search(tar,num/10)+(9-num%10)*search(tar,num/10-1);
    33 /*
    34 对于不大于个位数的数字都可以延伸1~num/10
    35 大于个位数的数字不考虑num/10
    36 */
    37     if(num<=lim)opt[num]=re;
    38 //可以记忆再记忆,不然就会数组越界
    39     return re;
    40 }
    41 
    42 void output()
    43 {
    44     for(int i=0;i<=9;i++)
    45         cout<<ans[i]<<endl;
    46 //输出答案
    47     fclose(stdin);
    48     fclose(stdout);
    49     return ;
    50 }
    51 
    52 int main()
    53 {
    54     input();
    55     for(int i=0;i<=9;i++)
    56     {
    57         memset(opt,0,sizeof(opt));
    58         ans[i]+=search(i,n);
    59 //针对0~9依次搜索
    60     }
    61     output();
    62     return 0;
    63 }
    View Code

    over~

  • 相关阅读:
    求职者:推销自己的四大妙招
    你的幸福,我的未来
    巧用close_trace命令释放误删trace文件
    转储控制文件信息
    _shared_pool_reserved_pct or shared_pool_reserved_size with ASMM
    【书籍推荐】Oracle 8i Internal Services
    【书籍推荐】Expert Oracle Practices
    Twitter将启动其在犹他州的客户数据中心
    facebook发布了Tornado V1.0
    latch free:cache buffer handles造成的SQL性能问题
  • 原文地址:https://www.cnblogs.com/qswx/p/9308521.html
Copyright © 2011-2022 走看看