【HDU】4734 F(x) 数位DP

传送门:【HDU】4734 F(x)


题目分析:发现F(x)最大不过4599,于是开一个dp[10][5000],dp[i][j]表示到第i位还剩j的大小能凑成的数的个数。然后就可以数位DP了,dp数组放在一开始初始化一次就可以了。

注意:第二位一定要是表示还剩下的大小,这样不会因为每次dp都要重新计算而超时(?或许也有更好的方法)。


代码如下:


#include <map>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std ;

typedef long long LL ;

#pragma comment ( linker , "/STACK:16777216" )
#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )
#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define clr( a , x ) memset ( a , x , sizeof a )

int dp[10][5000] ;
int digit[10] ;
int A , B ;

int dfs ( int cur , int limit , int sum ) {
	if ( sum < 0 ) return 0 ;
	if ( cur == -1 ) return 1 ;
	if ( !limit && ~dp[cur][sum] ) return dp[cur][sum] ;
	int ans = 0 , n = limit ? digit[cur] : 9 ;
	For ( i , 0 , n ) ans += dfs ( cur - 1 , limit && i == n , sum - i * ( 1 << cur ) ) ;
	return limit ? ans : dp[cur][sum] = ans ;
}

void solve () {
	int n1 = 0 , sum = 0 ;
	scanf ( "%d%d" , &A , &B ) ;
	rep ( i , 0 , 9 ) {
		sum += A % 10 * ( 1 << i ) ;
		A /= 10 ;
	}
	while ( B ) {
		digit[n1 ++] = B % 10 ;
		B /= 10 ;
	}
	int ans = dfs ( n1 - 1 , 1 , sum ) ;
	printf ( "%d\n" , ans ) ;
}

int main () {
	int T , cas = 0 ;
	scanf ( "%d" , &T ) ;
	clr ( dp , -1 ) ;
	while ( T -- ) {
		printf ( "Case #%d: " , ++ cas ) ;
		solve () ;
	}
	return 0 ;
}


你可能感兴趣的:(HDU)