1. 程式人生 > >51nod 1042 數字0-9的數量 (數位dp、dfs、前導0)

51nod 1042 數字0-9的數量 (數位dp、dfs、前導0)

alt start 限制 其中 算法 mit -s clas mem

1042 數字0-9的數量技術分享 基準時間限制:1 秒 空間限制:131072 KB 分值: 10 難度:2級算法題 技術分享 收藏 技術分享 關註 技術分享 取消關註 給出一段區間a-b,統計這個區間內0-9出現的次數。 比如 10-19,1出現11次(10,11,12,13,14,15,16,17,18,19,其中11包括2個1),其余數字各出現1次。 Input
兩個數a,b(1 <= a <= b <= 10^18)
Output
輸出共10行,分別是0-9出現的次數
Input示例
10 19
Output示例
1
11
1
1
1
1
1
1
1
1


終於過了,前導零太煩了。
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
ll ten[20]={1},a[20],dp[20];
void init()
{
    for(ll i=1;i<20;i++)
        ten[i]=ten[i-1]*10;
}
ll dfs(ll pos,ll num,ll lead,ll limit,ll who)
{
    if(pos==-1) return num;
    if(!limit&&dp[pos]!=-1&&!lead) return num*ten[pos+1]+dp[pos];
    ll up=limit?a[pos]:9;
    ll tmp=0;
    if(who!=0)
        for(int i=0;i<=up;i++)
        tmp+=dfs(pos-1,num+(who==i),0,limit&&a[pos]==i,who);
    else
        for(int i=0;i<=up;i++)
        tmp+=dfs(pos-1,num+(who==i&&!lead),lead&&i==0,limit&&a[pos]==i,who);
    if(!limit&&!lead) dp[pos]=tmp;
    return tmp;
}
ll solve(ll n,ll m)
{
    ll pos=0;
    while(n)
    {
        a[pos++]=n%10;
        n/=10;
    }
    return dfs(pos-1,0,1,1,m);
}
int main()
{
    ll x,y;
    ios::sync_with_stdio(false);
    init();
    cin>>x>>y;
    for(ll i=0;i<=9;i++)
    {
        memset(dp,-1,sizeof(dp));
        cout<<solve(y,i)-solve(x-1,i)<<endl;
    }
    return 0;
}

  

  

51nod 1042 數字0-9的數量 (數位dp、dfs、前導0)