[ZJOI2010][BZOJ1833] count 数字计数|模拟
1833: [ZJOI2010]count 数字计数
Time Limit: 3 Sec Memory Limit: 64 MBSubmit: 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; }