http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2745
终于AC了,纠结了一天的一道题。。。。
题意: 给一个长度为N的string , 需要往里面填充一些0、1,约束条件就是N的任意一个substring的中0的个数和1的个数之差不能超过K。
算法: DP
分析: 一开始没有看到substring 。 以为就是要求整个序列0的个数和1 的个数不超过K,一敲,果断WA,看了一下N的值,发现会超出int,该了long long ,2交,还是WA。。 重新看题目,发现是substring,才意识到自己错了。 。。 想了半天,经分析得:对于每一个状态下的后一位数是应该放0 还是1 ,其实就是取决于包括本字母在内的整个字符串的后缀中0、1的个数差是否满足条件,那只需要记录下每个状态下,前一个串的后缀中0、1差的最大值就可以了,因为状态就得到了。。
dp[i][k1][k2] 表示前i个字符串中,后缀满足max{ |0| - |1| }=k1 ; max{|1| - |0|} = k2 ;的种数;
代码:
/*
ZOJ 2745 01-K Code
Tips: DP
Language C++
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int N,K;
long long dp[65][65*2][65*2] ;
void DP()
{
memset(dp,0,sizeof(dp));
dp[1][64][66] = 1 ;
dp[1][66][64] = 1 ;
for(int i=1;i<=N;i++)
{
for(int j=-i+65;j<=i+65;j++)
{
for(int k=-i+65;k<=i+65;k++)
{
int k1 = j-65; int k2 = k-65 ; //考虑到k1可能为负值,因此加上一个数。
if(abs(k1+1)<=K && abs(k2-1)<=K)
{
long long num = (k1+1>1 ? k1 : 0 )+ 1 ;
dp[i+1][num+65][k2-1+65] += dp[i][j][k] ;
}
if(abs(k1-1)<=K && abs(k2+1)<=K){
long long num = (k2+1>1 ? k2 : 0 ) + 1 ;
dp[i+1][k1-1+65][num+65] += dp[i][j][k] ;
}
}
}
}
long long ans= 0 ;
for(int i=-N+65;i<=N+65;i++)
for(int j=-N+65;j<=N+65;j++)
{
ans += dp[N][i][j] ;
}
printf("%lld\n",ans);
}
int main()
{
while(scanf("%d %d",&N,&K)!=EOF)
{
DP();
}
return 0 ;
}