[ZJOI2010][BZOJ1833] count 数字计数|模拟

1833: [ZJOI2010]count 数字计数

Time Limit: 3 Sec  Memory Limit: 64 MB
Submit: 1976  Solved: 873
[Submit][Status][Discuss]

Description

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

Input

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

Output

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

Sample Input

1 99

Sample Output

9 20 20 20 20 20 20 20 20 20

HINT

30%的数据中,a<=b<=10^6;
100%的数据中,a<=b<=10^12。

Source

 
不会数位dp的渣渣就默默地写成了模拟。。。
可以手动模拟或者打表找一下规律
计算一下0-9,0-99,0-999...内每个数字出现的次数。
表如下
0-9              1               1
0-99             10              20
0-999            190            300
0-9999           2890           4000
0-99999           38890          50000
...
 
规律已经很明显了……不要忘记处理0的情况。
 
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll ans[10],m[15],ansb[10];
ll a,b;
inline void work(ll x)
{
    char s[15];
    int ss[15];
    sprintf(s+1,"%lld",x);
    int len=strlen(s+1);
    for (int i=1;i<=len;i++) ss[i]=s[len-i+1]-'0';
    for (int i=len;i>0;i--)
    {
        for (int j=0;j<=9;j++) ans[j]+=m[i-1]*(i-1)*ss[i];
        for (int j=0;j<ss[i];j++) ans[j]+=m[i];
        ans[ss[i]]+=x%m[i]+1;
    }
    for (int i=2;i<=len;i++) ans[0]-=m[i];
}
int main()
{
    m[1]=1;
    for (int i=2;i<=15;i++) m[i]=m[i-1]*10;
    scanf("%lld%lld",&a,&b);
    work(b);
    for (int i=0;i<=9;i++) ansb[i]=ans[i];
    memset(ans,0,sizeof(ans));
    work(a-1);
    for (int i=0;i<=8;i++) printf("%lld ",ansb[i]-ans[i]); printf("%lld",ansb[9]-ans[9]);
    return 0;
}
    

 


posted @ 2015-08-28 11:03  ws_fqk  阅读(228)  评论(0编辑  收藏  举报