1833: [ZJOI2010]count 数字计数
Time Limit: 3 Sec Memory Limit: 64 MBSubmit: 1208 Solved: 552
[ Submit][ Status]
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。
【题解】数位DP,建一个数组 f [ i ][ j ][ k ], i表示第 i 位,j 表示最高位是 j ,k 表示0~9出现个数。然后通过一系列的处理得到答案。计算的过程数值很大,记得开long long.
#include<cstdio>
#include<cstring>
#define LL long long
int ax[15],bx[15];
LL f[15][10][10],va[15],vb[15];
inline void swap(LL &x,LL &y){LL t=x;x=y;y=t;}
inline LL ff(int x){
LL tot=1;
for(int i=1;i<=x;i++)tot*=10;
return tot;
}
int main()
{
LL a,b;int la=0,lb=0;
scanf("%lld%lld",&a,&b);
if(a>b)swap(a,b);b++;
while(b){
bx[++lb]=b%10;b/=10;
}
while(a){
ax[++la]=a%10;a/=10;
}if(!la)ax[++la]=0;
memset(f,0,sizeof(f));
for(int i=0;i<=9;i++)f[1][i][i]=1;
for(int i=2;i<=lb;i++)
for(int j=0;j<=9;j++)
{
for(int k=0;k<=9;k++)
for(int p=0;p<=9;p++)f[i][j][p]+=f[i-1][k][p];
f[i][j][j]+=ff(i-1);
}
memset(vb,0,sizeof(vb));
if(bx[lb])
for(int i=1;i<=bx[lb]-1;i++)
for(int j=0;j<=9;j++)vb[j]+=f[lb][i][j];
for(int i=lb-1;i;i--)
{
for(int j=1;j<=9;j++)
for(int k=0;k<=9;k++)vb[k]+=f[i][j][k];
for(int p=i+1;p<=lb;p++)
for(int k=0;k<=bx[i]-1;k++)
vb[bx[p]]+=ff(i-1);
if(bx[i])
for(int k=0;k<=bx[i]-1;k++)
for(int j=0;j<=9;j++)vb[j]+=f[i][k][j];
}
memset(va,0,sizeof(va));
if(ax[la])
for(int i=1;i<=ax[la]-1;i++)
for(int j=0;j<=9;j++)va[j]+=f[la][i][j];
for(int i=la-1;i;i--)
{
for(int j=1;j<=9;j++)
for(int k=0;k<=9;k++)va[k]+=f[i][j][k];
for(int p=i+1;p<=la;p++)
for(int k=0;k<=ax[i]-1;k++)
va[ax[p]]+=ff(i-1);
if(ax[i])
for(int k=0;k<=ax[i]-1;k++)
for(int j=0;j<=9;j++)va[j]+=f[i][k][j];
}
for(int i=0;i<=9;i++)vb[i]-=va[i];
printf("%lld",vb[0]);
for(int i=1;i<=9;i++)printf(" %lld",vb[i]);
printf("\n");
return 0;
}