您的位置:首页 > 移动开发

hdu 4906 Our happy ending (多校第4场 )状压DP

2014-08-04 18:02 459 查看
题目大意:

如果一个串有和为 k 的子串,那么这个串就是一个好的串。这串数字有 n 位,每位的数字可以是 0 - L。 要求,求出这样的串有多少个。其中 0 1 与 1 0 这样的算作不同的串。

解题思路:

dp[i] = j;其中 i 转换为二进制,1 表示可以求得该位,0 表示不可求得。j 表示 种数。 比如说: dp[5] = 3. 因为5 的二进制是 1 0 1 所以 和为 1 的串有 3 个 和为 3 的串也有 3 个。和为 2 的串不可求,因为5转换为二进制后,第二位是0.

所以,对于第 i 位,我们可以从 第 i - 1 位的情况下 递推过来。j | ( ( j << ( t ) ) & tem ) | ( 1 << ( t - 1 ) ); j表示前一个状态,t表示该数字是 t 。

最后还要加上 在 1-k 之外的数字。

具体代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL __int64
const int mod = 1e9+7;
LL dp[(1<<20)+40];
int main()
{
LL y;
int T,n,m,i,j,k,l,x,t;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&k,&l);
m = min(k,l);
x = l-m;
memset(dp,0,sizeof(dp));
dp[0] = 1;
LL tem = (1<<k)-1;
for(i=1; i<=n; i++)
{
for(j=tem; j>=0; j--)//该循环的顺序不能变,因为dp只有一维,如果有两维,并且其中一维表示第i个数字那么就没关系了
{
if(dp[j]==0)continue;//节约时间,防止超时
y = dp[j];
for(t=1; t<=m; t++)
{
int next = j|((j<<(t))&tem)|(1<<(t-1));
dp[next] += y;
dp[next] %= mod;
}
dp[j]+=y*x;
dp[j] %= mod;
}
}
LL ans = 0;
int z = (1<<(k-1));
if(k<=0)z =0;
for(i=z; i<=tem; i++)//加上所有能到达和为 k 的串的数量
ans += dp[i],ans%=mod;
printf("%I64d\n",ans%mod);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  hdu 动态规划 dp