• 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
    输出包含1的个数
    Input示例
    12
    Output示例
    5
    第一次写数位dp还是挺头疼的啊,dp[i][j]表示以j开头的i位数x=(j+1)*pow(10,i-1)-1,1-x之间所有的数中1出现的次数。
    不难写出方程 dp[i][j]=dp[i][j-1]+dp[i-1][9] 这个自己模拟一下就知道了,
    特殊的对于 dp[i][0]=dp[i-1][9] ;
    当j==1时上面的方程也要变化为 dp[i][1]=dp[i][j-1]*2+pow(10,i-1),这是因为最高位的'1'不能被忽略
    之后对于每次询问的数将他依次拆解计算,
    例如对于N=3456,我们先拆出来 [1,2999],也就是 dp[4][2] ,容易发现剩下的数就是 3000-3456,但是3!=1,所以这一段<==> 1-456,这样每次计算一位就ok,
    特殊的对于出现1的位置例如 1234,我们加上dp[4][0]之后剩下的数是 1000-1234,这个1显然不能抛弃,我们加上234+1个'1'之后再把数转化为 1-234计算就好了。
    第一次写所以写了个暴力对拍!


    注意枚举低位的时候如果高位有1,统计一下所有高位的1,乘上当前区间内数的个数。
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int f[15][10];
     4 int bit[15];
     5 int p10[10]={1};
     6 int cal(int N){
     7     int ans=0,len=0,ok=0;
     8     while(N){
     9         bit[len++]=N%10;
    10         N/=10;
    11     }
    12     bit[len]=-1;
    13     for(int i=len-1;i>=0;--i){
    14         for(int k=0;k<bit[i];++k){
    15             ans+=f[i+1][k];
    16             int tot=0;
    17             for(int j=i+1;j<len;j++){
    18                 if(bit[j]==1){
    19                     tot++;
    20                 }
    21             }
    22             ans+=tot*p10[i];
    23         }
    24     }
    25     return ans;
    26 } 
    27 int main(){
    28     int i,j,k;
    29     for(i=1;i<10;++i) p10[i]=p10[i-1]*10;
    30     f[1][1]=1;
    31     for(i=2;i<=10;++i){
    32         for(j=0;j<10;++j){
    33             for(k=0;k<10;++k){
    34                 f[i][j]+=f[i-1][k];
    35             }
    36             if(j==1) f[i][j]+=p10[i-1];
    37         }
    38     }
    39     
    40     int N;
    41     while(scanf("%d",&N)==1)
    42             printf("%d
    ",cal(N+1));
    43     return 0;
    44 }

      f[i]表示所有的i位数中包含1的个数,有前导零的数也计算在内,因为在计算高位时低位可以为零。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define LL long long 
     4 LL f[15]={0,1};
     5 LL p10[15]={1,1};
     6 int bit[15];
     7 void init(){
     8     for(int i=1;i<=10;++i) p10[i]=p10[i-1]*10;
     9     for(int i=2;i<=10;++i) f[i]=f[i-1]*10+p10[i-1];
    10 }
    11 LL cal(int N){
    12     int len=0;
    13     while(N){
    14         bit[len++]=N%10;
    15         N/=10;
    16     }
    17     bit[len]=-1;
    18     LL ans=0,one=0;
    19     for(int i=len-1;i>=0;--i){
    20         ans+=f[i]*bit[i];
    21         if(bit[i]>1) ans+=p10[i];
    22         ans+=p10[i]*bit[i]*one;
    23         if(bit[i]==1) one++;
    24     }
    25     return ans;
    26 }
    27 int main(){
    28     int n,i,j,k;
    29     init();
    30     while(scanf("%d",&n)==1){
    31         printf("%lld
    ",cal(n+1));
    32     }
    33     return 0;
    34 }
  • 相关阅读:
    Java中的Iterable与Iterator详解
    1、JAVA数据类型
    maven 国内阿里云镜像配置
    数据库优化以及SQL优化小结
    用IDEA生成javadoc文档
    Elastic Search 新手笔记(1)——入门篇
    MQ技术选型
    springboot + aop + Lua分布式限流的最佳实践
    go 变量声明作用域问题
    android 开发环境变量配置
  • 原文地址:https://www.cnblogs.com/zzqc/p/7400211.html
Copyright © 2020-2023  润新知