poj3286--How many 0's?(数位dp)

来源:互联网 发布:诈骗软件怎么举报 编辑:程序博客网 时间:2024/06/07 16:48

题目链接:点击打开链接

题目大意:给出m和n(n>=m),求m到n区间内的0的个数和。

数位dp,注意统计前缀为0的,和要求的数的高位存在0,对低位的影响。

#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;#define LL __int64LL dp[12][10] , num[12] ;void init() {    int i , j , k ;    memset(dp,0,sizeof(dp)) ;    dp[1][0] = 1 ;    for(i = 2 , num[1] = 1; i < 12 ; i++)        num[i] = num[i-1]*10 ;    for(i = 2 ; i < 12 ; i++) {        dp[i][0] = num[i] ;        for(j = 0 ; j < 10 ; j++) {            for(k = 0 ; k < 10 ; k++) {                dp[i][j] += dp[i-1][k] ;            }        }    }    return ;}LL solve(LL x) {    int a[12] , cnt = 0 , i , j ;    LL sum , s = 0 ;    if( x ) sum = 1 ;    else sum = 0 ;    while( x ) {        a[++cnt] = x%10 ;        x /= 10 ;    }    if( !cnt ) a[++cnt] = 0 ;    for(i = cnt ; i > 0 ; i--) {        if( a[i] == 0 ) s++ ;        for(j = 0 ; j < a[i] ; j++) {            if( i == cnt && j == 0 ) continue ;            sum += dp[i][j] ;            sum += s*num[i] ;        }        if( i == cnt ) continue ;        for(j = 1 ; j <= 9 ; j++)            sum += dp[i][j] ;    }    return sum ;}int main() {    LL n , m , ans ;    init() ;    while( scanf("%I64d %I64d", &m, &n) != EOF ) {        if( m == -1 && n == -1 ) break ;        ans = solve(n) - solve(m) ;        do{            if( n%10 == 0 ) ans++ ;            n /= 10 ;        }while( n ) ;        printf("%I64d\n",  ans) ;    }    return 0 ;}


1 0