您的位置:首页 > 其它

BSOJ: 2697 -- 【ZJOI2010】数字计数

2016-05-22 11:24 351 查看

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,好久都没刷过题了,居然搞了半小时。

我开了四维的数组,不知道还能不能优化。

p是要计算出现个数的数字(0→9)(0\to 9)

sum是之前这个数字出现次数。

flag1是判断之前有没有非0数,主要是为了针对0的计算。

建议人工模拟下,更能理解。

代码如下:

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
long long F[20][10][15][2];
int c[100];
long long Cal(int x,int p,int sum,int flag1,int flag){
if(!x)return sum;
if(!flag&&F[x][p][sum][flag1])return F[x][p][sum][flag1];
int k=flag?c[x]:9;
long long ret=0;
for(int i=0;i<=k;i++){
ret+=Cal(x-1,p,sum+((i==p)&&((flag1&&p==0)||(p!=0))),flag1||(i!=0),flag&&(i==k));
}
return flag?ret:F[x][p][sum][flag1]=ret;
}
long long Ask(long long x,int k){
c[0]=0;
while(x){c[++c[0]]=x%10;x/=10;}
return Cal(c[0],k,0,0,1);
}
int main(){
long long a,b;
scanf("%lld%lld",&a,&b);
for(int i=0;i<=9;i++){
printf("%lld ",Ask(b,i)-Ask(a-1,i));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: