• UVA 1640 The Counting Problem(按位dp)


    题意:给你整数a、b,问你[a,b]间每个数字分解成单个数字后,0、1、2、3、4、5、6、7、8、9,分别有多少个

    题解:首先找到[0,b]与[0,a-1]进行区间减法,接着就只是求[0,x]

       对于x首先求出他有几位、接着从高位到低位求每个区间

       例如x=15602,则依次求出[1,9],[10,99],[100,999],[1000,9999],这个注意因为没有前导0,所以1-9是一样多的0要少一些

       接着再求[10000,10999],[11000,11999],[12000,12999],[13000,13999],[14000,14999],[15000,15099]..........[15500,15599]

       注意在这儿需求前导0,最后对于个位数的几个进行遍历就好了

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<vector>
    #include<string>
    #include<cstdio>
    #include<cstring>
    #include<iomanip>
    #include<stdlib.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define eps 1E-8
    /*注意可能会有输出-0.000*/
    #define sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型
    #define cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化
    #define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0
    #define mul(a,b) (a<<b)
    #define dir(a,b) (a>>b)
    typedef long long ll;
    typedef unsigned long long ull;
    const int Inf=1<<28;
    const ll INF=1LL<<60;
    const double Pi=acos(-1.0);
    const int Mod=1e9+7;
    const int Max=200010;
    int Dig[10]= {1,9,90,900,9000,90000,900000,9000000,90000000,900000000}; //1-9 10-99 100-999的总个数
    int makeup[10]= {0,1,10,100,1000,10000,100000,1000000,10000000,100000000}; //补全1-9并减去0
    int dp1[10];//[0,a-1]中0到9的个数
    int dp2[10];//[0,b]中0到9的个数
    void Everyno(int k,int *dp)//计算有k位的dp,例如k=2就是 10-99,不补前导0
    {
        int num=Dig[k-1]*k;
        for(int i=0; i<10; ++i)
        {
            if(!i)
                dp[i]=dp[i]+num-makeup[k-1]*9;//减去一些0不可能出现的地方
            else
                dp[i]=dp[i]+num+makeup[k-1];
        }
    }
    void Everyyes(int k,int *dp)
    {
        int num=makeup[k]*k;
        for(int i=0;i<10;++i)
        {
            dp[i]+=num;
        }
    }
    void Solve(int a,int* dp)//[0,a]中0到9的个数
    {
        for(int i=0; i<10; ++i)
            dp[i]=0;
        int enn=9;
        int dig=1;//位数
        while(enn<=a)//计算 1-9 10-99 100-999...除开0以外,每位个数都相同且平分差值
        {
            Everyno(dig,dp);
            dig++;
            enn=enn*10+9;
        }
    
        enn=enn/10+1;
       while(enn<=a)//剩下的数
        {
            dig=0;
        while(enn+Dig[dig+1]<=a)//例如求1899时 现在为1000,则需要使enn=1099
        {
            dig++;
            enn+=Dig[dig];
        }
        if(!dig)
            break;
        Everyyes(dig,dp);
        int temp=enn,temp2=dig;
        while(temp2--)
            temp/=10;
        while(temp)//补上前面的数,例如求1899在使用1000-1099时需要补上1与0的100个
        {
            dp[temp%10]+=makeup[dig+1];
            temp/=10;
        }
        enn++;
        }
    if(enn==1)
        enn--;
        while(enn<=a)//剩下个位几个
        {
            int temp=enn;
            if(temp==0)
                dp[0]++;
            while(temp)
            {
                dp[temp%10]++;
                temp/=10;
            }
            enn++;
        }
        return ;
    }
    int main()
    {
        int a,b;
        while(~scanf("%d %d",&a,&b)&&(a+b))
        {
            if(a>b)
                swap(a,b);
            Solve(a-1,dp1);
            Solve(b,dp2);
            for(int i=0; i<10; ++i)
                printf("%d%c",dp2[i]-dp1[i],i==9?'
    ':' ');
        }
        return 0;
    }

      

     其实还有更简单的方法:从后到前枚举每一个位置可能出现没一个值的个数,这儿可以通过打表找到一些规律

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<vector>
    #include<stdlib.h>
    #include<string>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define eps 1E-8
    /*注意可能会有输出-0.000*/
    #define Sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型
    #define Cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化
    #define mul(a,b) (a<<b)
    #define dir(a,b) (a>>b)
    typedef long long ll;
    const int Inf=0x3f3f3f3f;
    const double Pi=acos(-1.0);
    const int Max=10;
    ll Dp(ll n,int m)
    {
        ll num=0,k,l;
        if(!m)//0出现的次数是特殊的
        {
            k=0,l=1;
            while(l<n)
        {
            num+=((n-k)/(l*10)*l);
            //printf("%lld %lld %lld
    ",num,l,n);
             k=k*10+9;
            if((n-k)%(l*10)<=(k/10)&&(n-k)%(l*10)>0)
                num+=((n-k)%(l*10));
            l*=10;
        }
        }
        else//1-9出现的次数求法一致
        {
            k=1;
            l=m;
            while(n>=l)//从低到高枚举每一位
            {
                num+=(n-l)/(k*10)*k+min(k,(n-l)%(k*10)+1);
                k*=10;
                l*=10;
            }
        }
        return num;
    }
    int main()
    {
        ll n,m;
        while(~scanf("%lld %lld",&n,&m)&&(n+m))
        {
            if(n>m)
                swap(n,m);
            for(int i=0;i<10;i++)
                {
                     printf("%lld%c",Dp(m,i)-Dp(n-1,i),i==9?'
    ':' ');//枚举每个数
                }
        }
        return 0;
    }
  • 相关阅读:
    开发中的问题
    页面重定向Redirect时产生错误
    项目管理的几个阶段及分工
    让你的CSS像Jquery一样做筛选
    项目中的几个SQL程序
    SharePoint2010人员搜索配置心得
    TroubleShoot:该搜索请求无法连接到搜索服务
    转:软件架构师应该知道的97件事
    通用动态生成静态HTML页方法
    简单的正则表达式过滤网址
  • 原文地址:https://www.cnblogs.com/zhuanzhuruyi/p/6701073.html
Copyright © 2020-2023  润新知