zoukankan      html  css  js  c++  java
  • 数位DP

    基本思想在于将一个数拆分成每一位的数字,将总问题转化为子问题。

    例:求[a,b]中各个数字出现次数。 (luogu2602 数字计数)

    1.发现在i位数中(不考虑前导零),每一个数字出现的次数都相同。f[i]=f[i-1]*10+10^(i-1);

    2.在ABCD中,将其拆为:A000+B00+C0+D; A000中,考虑后三位每个数字出现次数都为:A*f[3];

    3.再加上第一位上小于A(从零开始,算前导零的时候会减去)的数出现了10^3次

    4.然而,后面的000~BCD中,每一个数的产生也伴随着A的一次出现,所以A出现次数单独加上BCD*1;

    5.处理前导零; 仅在开始填0~9999(len-1个)时会产生。 零的数量单独减去10^(len-1)+10^(len-2)+...+10+1;

    不用写两个query, 对于数组,传一个*就好。 详见代码:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=20;
    ll a,b;
    ll cnta[20],cntb[20];
    ll f[20],ten[20];
    void query(ll x,ll *cnt)
    {
        int len=0;
        int num[20];
        ll k=x;
        while(k)
        {
            num[++len]=k%10;
            k/=10;  
        }
        for(int i=len;i>=1;i--)
        {
            for(int j=0;j<=9;j++)
             cnt[j]=cnt[j]+f[i-1]*num[i];
            for(int j=0;j<num[i];j++)
             cnt[j]+=ten[i-1];
            ll num2=0;
            for(int j=i-1;j>=1;j--)
            {
                num2=num2*10+num[j];    
            }
            num2++;
            cnt[num[i]]+=num2;
            cnt[0]-=ten[i-1];
        }
    }
    int main()
    {
        scanf("%lld%lld",&a,&b);
        ten[0]=1;
        for(int i=1;i<=15;i++)
        {
            f[i]=f[i-1]*10+ten[i-1];
            ten[i]=ten[i-1]*10; 
        }
        query(a-1,cnta);
        query(b,cntb);
        for(int i=0;i<=9;i++)
         printf("%lld ",cntb[i]-cnta[i]);
        return 0;
    }

    luogu(P2602)

  • 相关阅读:
    由于版本依赖造成的YUM段错误
    CodeDom系列事件(event)定义和反射调用
    CodeSmith模板引擎系列二文件目录树
    F#初试打印目录文件树
    在IIS上SSL的部署和启动SSL安全
    CodeDom系列二程序基本结构符号三角形问题
    CodeDom系列目录
    CodeDom系列四Code生成
    CodeDom六实体类生成示例
    CodeDom系列五动态编译
  • 原文地址:https://www.cnblogs.com/Miracevin/p/9031693.html
Copyright © 2011-2022 走看看