现在的位置: 首页 > 综合 > 正文

HDU 4632 Palindrome subsequence(区间合并动态规划)

2019年03月02日 ⁄ 综合 ⁄ 共 1057字 ⁄ 字号 评论关闭

题意:给定T串只含小写字母的字符串,对于每串,输出回文字串的数目模10007

思路:区间合并,对于从第i个字符到第j个字符的串里面

          (1)如果str[i]!=str[j],则dp[i][j]=dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1],即回文串在[i,j-1]的情况数加上[i+1,j]的情况数,再减去两种重叠部分的情况数,即属于[i+1,j-1]的情况数。

          (2)如果str[i]==str[j],则dp[i][j]=(dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1])+(dp[i+1][j-1]+1)=dp[i+1][j]+dp[i][j-1]+1,即回文串在[i,j-1]的情况数加上[i+1,j]的情况数,再减去两种重叠部分的情况数,再加上由两端在同一个回文串中点所造成的新情况数,这些情况数为dp[i+1][j-1]+1(原来在[i+1,j-1]的回文串加上两端点造成的情况为dp[i+1][j-1],只含两端点的情况数为1,一共就是dp[i+1][j-1]+1)

          (3)注意i==j的情况,dp[i][j]=1。另外,中间过程可能会有负数,因此取模前要加上10007

#include<stdio.h>
#include<string.h>
#define M 10007
#define MAXN 1005
int ca=0,T,i,j,k,dp[MAXN][MAXN];
char str[MAXN];
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%s",str);
		int n=strlen(str);
		for(k=0;k<n;++k)
			for(i=0;i+k<n;++i)
			{
				j=i+k;
				if(!k) {dp[i][j]=1;continue;}//dp[i][i]=1;
				if(str[i]==str[j]) dp[i][j]=(dp[i+1][j]+dp[i][j-1]+1+M)%M;
				else if(k>1) dp[i][j]=(dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1]+M)%M;
				else dp[i][j]=(dp[i+1][j]+dp[i][j-1]+M)%M;//防止出现i+1>j-1的时候访问dp[i+1][j-1],此时显然dp[i+1][j-1]=0,直接略去
			}
		printf("Case %d: %d\n",++ca,dp[0][n-1]);
	}
	return 0;
}

抱歉!评论已关闭.