zoukankan      html  css  js  c++  java
  • hdu2089&&数圈圈(数位dp)

    题目链接:

    1,http://acm.hdu.edu.cn/showproblem.php?pid=2089

    2,https://www.nowcoder.com/acm/contest/30/D

    都是判断一个区间中的数字满足什么什么条件的有多少个,暴力的做法直接遍历,一个个数字的判断,然而数位dp很快,几乎在O(n*102),n是数字的位数,是非常快的

    数位dp也就是数位之间的dp,如十位与个位,百位与十位。在测试数据组数很多的话,可以预处理,但一般不必要,直接记忆化搜索,要方便得多

    数圈圈的AC代码:

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<iostream>
     4 #include<math.h>
     5 using namespace std; 
     6 typedef long long ll;
     7 ll dp[16][10]={0},pos[10],ning[20];
     8 
     9 ll pow1(ll a,ll b)
    10 {    ll sum=1;
    11     
    12     for(ll i=1;i<=b;i++)
    13         sum*=a;
    14     return sum;
    15     
    16 }
    17 
    18 ll dfs(int x) //x+1为位数,x为在数组中的位置 
    19 {    ll sum=0;
    20     if(x==-1) return dp[1][pos[x+1]];
    21     for(int i=0;i<pos[x];i++)  
    22         {    
    23             sum+=dp[x+1][i];
    24         
    25         }
    26     
    27     sum+=dfs(x-1);    
    28     if(x>0)        //需特判。。 
    29     {
    30         if(pos[x]==0||pos[x]==4||pos[x]==6||pos[x]==9)
    31             {    ll y=0;
    32                 for(int i=x-1;i>=0;i--)
    33                     y=y*10+pos[i];
    34                 
    35                 sum+=y+1;
    36             }
    37         if(pos[x]==8)
    38         {    ll y=0;
    39                 for(int i=x-1;i>=0;i--)
    40                     y=y*10+pos[i];
    41                 
    42                 sum+=2*(y+1);
    43             
    44         }
    45     }
    46     
    47     return sum;    
    48 }
    49 
    50 ll solve(ll x)
    51 {    int tot=0;
    52     if(x==0) return 0;
    53     while(x)
    54     {    
    55         pos[tot++]=x%10;
    56         x=x/10;
    57     }
    58 
    59     return dfs(tot-1)-ning[tot]; //减去前导0的影响        
    60 }
    61 
    62 int main()
    63 {    dp[1][0]=1,dp[1][4]=1,dp[1][6]=1,dp[1][8]=2,dp[1][9]=1; //预处理 
    64     ning[1]=1;
    65     for(int i=2;i<20;i++)
    66         ning[i]=ning[i-1]*10+1;
    67     for(ll i=2;i<16;i++)
    68         {    for(int j=0;j<10;j++)
    69                 {    
    70                     if(j==0||j==4||j==6||j==9)
    71                         dp[i][j]=pow1(10,i-1);
    72                     if(j==8) dp[i][j]=2*pow1(10,i-1);        
    73                         
    74                     for(int k=0;k<10;k++)
    75                         {    
    76                             dp[i][j]+=dp[i-1][k];
    77                         }
    78                 }    
    79             
    80         }
    81     int T;
    82     scanf("%d",&T);
    83     ll l,r;
    84     while(T--)
    85     {    scanf("%lld%lld",&l,&r);
    86         
    87         printf("%lld
    ",solve(r)-solve(l-1));
    88     }    
    89     
    90     
    91     return 0;
    92 } 
    View Code

    当时做了预处理,现在觉得还是直接记忆化搜索更方便,不用麻烦地特判处于上界的情况(如666,6就是每位的上界)

  • 相关阅读:
    linux笔记2.20
    新安装ubuntu后几项配置
    linux网络配置
    linux笔记2.19
    jquery在不同浏览器获取文件路径出现问题!
    软件工程师如何定义自己的职业路线
    标识符
    结对项目-四则运算 “软件”之升级版
    小学四则运算 “软件”之初版
    分布式版本控制系统Git的安装与使用
  • 原文地址:https://www.cnblogs.com/lnu161403214/p/8290552.html
Copyright © 2011-2022 走看看