您的位置:首页 > 其它

BZOJ-1833 [ZJOI2010]count 数字计数 数位DP

2017-06-10 20:27 483 查看

大家都很强, 可与之共勉。

1833: [ZJOI2010]count 数字计数

Time Limit: 3 Sec Memory Limit: 64 MB

Submit: 3440 Solved: 1518

[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

Day1

Day1

显然,我们可以先计算出[1,a-1],[1,b]中每个数字出现的个数,然后相减即可。问题变为:给一个数n,求1,2,…,n中每个数字出现的次数。

以下叙述中,“i位”都是从低位向高位数。

首先,我们允许前导0,也不考虑数大小的上限,在位数一定时,设为i,每种数字出现的次数是相同的,记为f(i)。不难得出递推式f(i)=10*f(i-1)+10^(i-1)(将第i位和前i-1位的数字分开考虑即可)。

继续,如果仍然允许前导0,但将数的上限考虑进来的话,我们只需要从高位向低位计算。设当前为第i位,n的这一位的数字为k,那么对于那些这一位数字小于k的数,他们的前i-1位是没有数的大小上限的,每个数字累加k*f(i-1)即可,同时0~k-1的数累加10^(i-1);而对于那些这一位的数字恰好为k的数,为了不超过上限,应累加前i-1位的数字形成的数+1。

最后,如何处理前导0呢?

其实,假设n有m位,我们只需要先统计出1,2,…m-1位数的情况(而这些是没有上限的,会比较方便),计算时而且保证这些数的首位不为0,然后对于m位同样的在最高位的时候不将0计算进来即可。

#include <cstdio>

int num[20] ;
long long a, b, f[20], pow[20] ;
long long cnta[10], cntb[10] ;

inline void Digit_Dp ( long long n, long long* cnt )  {
if ( !n )  return ;
long long N = n ;
int M ;
for ( M = 0 ; N ; num[++ M] = N % 10, N /= 10 ) ;
for ( int i = 1 ; i < M ; ++ i )  {
cnt[0] += f[i - 1] * 9 ;
for ( int j = 1 ; j < 10 ; ++ j )  cnt[j] += f[i - 1] * 9 + pow[i - 1] ;
}
n -= num[M] * pow[M - 1] ;
for ( int i = 1 ; i < num[M] ; ++ i )  cnt[i] += pow[M - 1] ;
for ( int i = 0 ; i < 10; ++ i )    cnt[i] += f[M - 1] * ( num[M] - 1 ) ;
cnt[num[M]] += n + 1 ;
for ( int i = M - 1 ; i ; -- i )  {
n -= num[i] * pow[i - 1] ;
for ( int j = 0 ; j < num[i] ; ++ j )  cnt[j] += pow[i - 1] ;
for ( int j = 0 ; j < 10; ++ j )    cnt[j] += f[i - 1] * num[i] ;
cnt[num[i]] += n + 1 ;
}
}

int main ( )  {
pow[0] = 1 ;
for ( int i = 1 ; i < 15 ; ++ i )  {
f[i] = f[i - 1] * 10 + pow[i - 1] ;
pow[i] = pow[i - 1] * 10 ;
}
scanf ( "%lld%lld", &a, &b ) ;
Digit_Dp ( a - 1, cnta ) ;
Digit_Dp ( b, cntb ) ;
for ( int i = 0 ; i <= 9 ; ++ i )
printf ( "%lld%c", cntb[i] - cnta[i], ( i ^ 9 ) ? ' ' : '\n' ) ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: