哎卧槽 ,刷了这么多dp了,妈蛋这题还是tle了啊卧槽
好久没刷过难一点的数位dp了
这题的状态表示不能记录以及用了多少,而是还剩下多少
因为t太大 不能重复每次的计算
那么当dp[sum][pos]表示还有pos+1位还有sum大小能用,有多少种可能
这样的话就与B和A无关了
但是当dp[sum][pos]表示还有pos+1位已经用了sum大小时,那么最终的结果将于fa有关,则不不能重复利用
所以应采取第一种状态的表示
AC代码如下:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
int dp[22000][12];
int A, B, digit[12], fa, cnt;
int tt[15];
int DFS( int pos, int pre, int statu ){
if( pre < 0 ){
return 0;
}
if( pos < 0 ){
if( pre >= 0 ){
return 1;
}else{
return 0;
}
}
if( !statu && dp[pre][pos] != -1 ){
return dp[pre][pos];
}
int ans = 0;
int ends = statu ? digit[pos] : 9;
for( int i = 0; i <= ends; i++ ){
ans += DFS( pos - 1, pre - i * tt[pos], statu & ( i == ends ) );
}
if( !statu ){
dp[pre][pos] = ans;
}
return ans;
}
int solve(){
cnt = 0;
while( A ){
digit[cnt++] = A % 10;
A /= 10;
}
fa = 0;
for( int i = 0; i < cnt; i++ ){
fa += digit[i] * tt[i];
}
cnt = 0;
while( B ){
digit[cnt++] = B % 10;
B /= 10;
}
return DFS( cnt - 1, fa, 1 );
}
int main(){
int T, Case = 1;
tt[0] = 1;
for( int i = 1; i <= 14; i++ ){
tt[i] = tt[i-1] * 2;
}
memset( dp, -1, sizeof( dp ) );
scanf( "%d", &T );
while( T-- ){
scanf( "%d%d", &A, &B );
printf( "Case #%d: %d\n", Case++, solve() );
}
return 0;
}