您的位置:首页 > 其它

hdu 4352 数位DP

2013-08-25 22:18 232 查看
这一题要用状态压缩,不然你会TLE到死的。

但是一开始的时候我也想不通为什么状态压缩能够节省时间,最后发现在状态压缩的时候用了点规律。

比如说 对于 1672345这个状态, 开始时候保存167 然后进行到第四位的时候 用2 替换6然后 用4替换7 然后增加5 这样DFS更深之后状态就变成了12345 这样就实现了在2345虽然都小于7但是还是能够更新。(利用了注释 11111 和 22222 )

还有应该把算出来的dp保存起来 供下个测试使用。注意还有[K]这个维度!!!!!

还有一点!!!!!!!!!我敲代码的时候把1敲成了i 连测试都过不了 找了半天啊!!!!!!!!!!都快瞎了我的眼啊!!!!!!!!!坑!!!!




AC代码如下:

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

__int64 dp[20][1<<10][11];//不能少了[K]这个维度,不然会超时!!!
__int64 L, R, K;
int digit[20];
int len;

__int64 DFS( int pos, int length, int statu, bool limit ){// 表示 进行到第pos位、最长子序列为length、序列为statu、状态是limit 时还有多少种情况!!!
if( pos == 0 ){
return length == K;
}
if( !limit && dp[pos][statu][K] != -1 ){
return dp[pos][statu][K];
}
__int64 ans = 0;
int end = limit ? digit[pos] : 9;
for( int i = 0; i <= end; i++ ){
if( statu || i  ){
if( statu < ( 1 << i ) ){//1111111111
ans += DFS( pos - 1, length + 1, statu | ( 1 << i ), limit && i == end );
}else if( statu & ( 1 << i ) ){
ans += DFS( pos - 1, length, statu, limit && i == end );
}else{//222222222222
for( int j = i + 1; j <= 9; j++ ){
if( statu & ( 1 << j ) ){
ans += DFS( pos - 1, length, ( statu | ( 1 << i ) ) ^ ( 1 << j ), limit && i == end );
break;
}
}
}
}else{
ans += DFS( pos - 1, 0, 0, limit && i == end );
}
}
if( !limit ){
dp[pos][statu][K] = ans;
}
return ans;
}

__int64 solve( __int64 N ){
if( N == 0 ){
return 0;
}
len = 0;
while( N ){
digit[++len] = N % 10;
N /= 10;
}
return DFS( len, 0, 0, true );
}

int main(){
int T, Case = 1;
cin >> T;
memset( dp, -1, sizeof( dp ) );
while( T-- ){
cin >> L >> R >> K;
printf( "Case #%d: %I64d\n", Case++, solve( R ) - solve( L - 1 ) );
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: