http://acm.hdu.edu.cn/showproblem.php?pid=3709
题意:
求[x , y]内的平衡数的个数。 0<=x ,y <=10^18
思路:
数位dp。先枚举pivot点,然后逐位进行确定,为了便于处理,dp的时候我们将左右力矩合在一起考虑,即左边的力矩是正的,右边的力矩用负的表示。状态为:dp[pos][ pivot ][ sum ]表示后面pos位在不受大小限制的情况下,且支点在pivot点,力矩和为sum时的种数。
代码:
#include <stdio.h>
#include <string.h>
typedef __int64 LL ;
LL x, y ;
int digit[22] , pos ;
LL dp[22][22][1600] ;
LL dfs(int pos, int pivot , int s , int limit ){
if( pos == 0 ) return ( s == 0 ) ;
if( s < 0 ) return 0 ;
if( !limit && dp[pos][pivot][s] != -1 ) return dp[pos][pivot][s] ;
int end = limit ? digit[pos] : 9 ;
LL res = 0 ;
int n_s ;
for(int i=0;i<=end;i++){
n_s = s + ( pos - pivot) * i ;
res += dfs( pos-1 , pivot , n_s , limit&(i==end) ) ;
}
if( !limit ) dp[pos][pivot][s] = res ;
return res ;
}
LL cal( LL n ){
if( n==-1 ) return 0 ;
if( n==0 ) return 1 ;
pos = 0 ; LL tmp = n ;
while( tmp ){
digit[ ++pos ] = tmp % 10 ; tmp /= 10 ;
}
LL sum = 0 ;
memset( dp , -1 , sizeof(dp) );
for( int i=pos;i>=1;i-- ){
sum += dfs( pos , i , 0 , 1 ) ;
}
sum -= ( pos - 1 );
return sum ;
}
int main(){
int T ; scanf("%d",&T);
for( int cas = 1 ; cas <= T ; cas ++ ){
scanf("%I64d %I64d",&x,&y) ;
printf("%I64d\n", cal(y) - cal(x-1) ) ;
}
return 0;
}