数位dp

有这么一道板子

题目描述

给定两个正整数 aa 和 bb,求在 [a,b][a,b] 中的所有整数中,每个数码 (digit) 各出现了多少次。

输入格式

输入文件中仅包含一行两个整数 aa、bb,含义如上所述。

输出格式

输出文件中包含一行 1010 个整数,分别表示 090−9 在 [a,b][a,b] 中出现了多少次。

 

可以记忆化搜索,

如图hzwer的一样,

 

裸的数位dp

 

大概只有我这种逗比不会做

 

递推出f[i][j][k]表示长度为i开头j的所有数字中k的个数

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<cstring>
 7 #define ll long long 
 8 using namespace std;
 9 inline ll read()
10 {
11     ll x=0,f=1;char ch=getchar();
12     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
13     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
14     return x*f;
15 }
16 struct data{ll a[10];};
17 ll a,b,t[25];
18 data f[25][10];
19 data operator+(data a,data b)
20 {
21     data t;
22     for(int k=0;k<=9;k++)
23         t.a[k]=a.a[k]+b.a[k];
24     return t;
25 }
26 data cal(ll x)
27 {
28     data ans;for(int i=0;i<=9;i++)ans.a[i]=0;
29     if(!x)
30     {
31         ans.a[0]=1;
32         return ans;
33     }
34     int len=15;
35     while(t[len]>x)len--;
36     for(int i=1;i<len;i++)
37         for(int j=1;j<=9;j++)
38             ans=ans+f[i][j];
39     ans.a[0]++;
40     int cur=x/t[len];
41     for(int i=1;i<cur;i++)
42         ans=ans+f[len][i];
43     x%=t[len];
44     ans.a[cur]+=x+1;
45     for(int i=len-1;i;i--)
46     {
47         cur=x/t[i];
48         for(int j=0;j<cur;j++)
49             ans=ans+f[i][j];
50         x%=t[i];
51         ans.a[cur]+=x+1;
52     }
53     return ans;
54 }
55 int main()
56 {
57     t[1]=1;for(int i=2;i<=15;i++)t[i]=t[i-1]*10;
58     for(int i=0;i<=9;i++)f[1][i].a[i]=1;
59     for(int i=2;i<=12;i++)
60         for(int x=0;x<=9;x++)
61             for(int y=0;y<=9;y++)
62             {
63                 f[i][y]=f[i][y]+f[i-1][x];
64                 f[i][y].a[y]+=t[i-1];
65             }
66     a=read();b=read();
67     data t1=cal(b),t2=cal(a-1);
68     for(int i=0;i<=9;i++)
69     {
70         printf("%lld",t1.a[i]-t2.a[i]);
71         if(i!=9)printf(" ");
72     }
73     return 0;
74 }

 

我还能搜索

#include <cstdio>
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

#define ls (t<<1)
#define rs ((t<<1)|1)
#define mid ((l+r)>>1)

#define mk make_pair
#define pb push_back
#define fi first
#define se second

ll p[20];
ll ans[11]={};
void chushi() {
    p[0]=1;
    for (int i=1;i<18;i++) {
        p[i]=p[i-1]*10;
    }
    //用于取某一位数 
}

void dfs(ll x,int f) {
    //x为终点 
    if (x==-1) {
        ans[0]++;
        return;
    }
    for (int k=1;k<10;k++) { 
        for (int i=1;i;i++) {
            //取现在位数 
            ll l=x/p[i];
            ll r=x%p[i-1];
            ll now=x%p[i]/p[i-1];
            if (now>k) {
                ans[k]+=(l+1)*p[i-1]*f;
            }
            else if(now==k) {
                ans[k]+=(l*p[i-1]+r+1)*f;
            }
            else ans[k]+=l*p[i-1]*f;
            if (p[i]>x) break;
        }
    }
    for (int i=1;i;i++) {
        //单独处理0 
        ll l=x/p[i];
        ll r=x%p[i-1];
        ll now=x%p[i]/p[i-1];
        if (now>0) ans[0]+=l*p[i-1]*f;
        else ans[0]+=((l-1)*p[i-1]+r+1)*f;
        if (p[i]>x) break;
    }
}
ll n,m; 

int main() {
    cin>>n>>m;
    chushi();
    dfs(m,1);
    dfs(n-1,-1);
    for (int i=0;i<=9;i++) {
        cout<<ans[i]<<" ";
        if (i==9) cout<<endl;
    }
    return 0;
}

 

还需好好理解理解


 

posted @ 2018-10-20 15:57  codemaker_li  阅读(168)  评论(0编辑  收藏  举报