您的位置:首页 > 其它

hdu 4906 状态压缩DP

2014-08-01 22:49 330 查看
这题比赛的时候没能做出来,看的点击打开链接的思路

在比赛的时候一开始老想着数位DP,最后发现不行,在数位DP的时候按求和能产生的数来DP,最后发现这样是不行的,因为一个数能够贡献多个和,这样在DP的过程中就重复计算了。

比方说,1 2 3 这三个数能贡献 1 2 3 4 5 6 ,在之后的过程中他们又分别贡献不同的和,那么在最后统计的时候本来是由一种1 2 3 变来 却贡献了多次

然后在比赛最后才感觉是不是要用个st来状态压缩一下,,,,然后当时hdu挂了。。。也不想做了(虽然继续想也想不出来



蒟蒻)

这题怎么做呢?

用个st来表示一个数的状态:st的第i位如果为1的话就表示这组数能够产生和 i - 1

然后这样的话每组数就只能贡献一个st了。。。这样就不会重复

然后dp【i】【st】就表示前i位集合为st的个数

然后每次就是用1到L来DP

类似背包。。。。。

然后这题,在比赛的时候告诉数据是不会为0的,所以不用从0开始

还有一点,,,,有个地方要优化一下,,,在代码中,,,不优化会TLE

AC代码如下:

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

const int MOD = 1e9 + 7;

int N, K, L;
int dp[(1<<20)+10];

int main(){
int T;
scanf( "%d", &T );
while( T-- ){
scanf( "%d%d%d", &N, &K, &L );
int t;
if( L > K ){
t = L - K;
L = K;
}else{
t = 0;
}
memset( dp, 0, sizeof( dp ) );
dp[0] = 1;
for( int i = 1; i <= N; i++ ){
for( int j = (1<<K) - 1; j >= 0; j-- ){
if( dp[j] == 0 )    continue;//没有这里会TLE
__int64 tt = (__int64)t * dp[j] % MOD;
int temp = dp[j];
for( int l = L; l >= 1; l-- ){
int new_st = j | (1<<(l-1)) | ( (j<<l) & ((1<<K)-1) );
dp[new_st] = ( dp[new_st] + temp ) % MOD;
}
dp[j] = ( dp[j] + tt ) % MOD;
}
}
int ans = 0;
for( int i = 0; i < ( 1 << ( K ) ); i++ ){
if( ( 1 << ( K - 1 ) ) & i ){
ans = ( ans + dp[i] ) % MOD;
}
}
printf( "%d\n", ans );
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: