pku1159 Palindrome DP

有一个感悟就是一大群人指着错的东西硬说是对的= =

MLE后想了下答案最大也就5000,然后改成short int 就可以了,A掉之后翻了下discuss,然后看到了一条定理:答案是长度减去与反串的最长公共子串= =当时我就懵逼了赶快手写了一组数据发现是错的,然而似乎子序列就对了

然后我点开回复一条一条的看看到一条这样的:

哥/姐,最长子列不要连续地.........
大侠连最长公共子序列都没搞懂。。
虽然这是一条2011年的评论但是我还是回了一句,既然你知道是子序列那你说lz是对的?

一脸懵逼

好吧现在我知道了两种做法,一种是像之间的DNA配对的PKU1141那样当作增加一个字符默认与另外一个字符匹配那样的类似区间DP的写法

一种是求出原串与反串的最长公共子序列长度再用原串长度减去即为答案,证明其实也很简单,脑补一下就好惹,都是N2的

还有听说滚动数组能有很大优化?然后再动态一下就更小了?

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define LL long long
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define down(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
inline LL read()
{
	LL d=0,f=1;char s=getchar();
	while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
	while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
	return d*f;
}
#define N 5005
#define inf 65534
char s[N];
unsigned short int f[N][N];
int n;

int dfs(int i,int j)
{
	if(i>j)return f[i][j]=0;
	if(f[i][j]!=inf)return f[i][j];
	if(s[i]==s[j])
	{
		int ret=dfs(i+1,j-1);
		f[i][j]=ret;
	}else
	{
		int ret1=dfs(i+1,j);
		int ret2=dfs(i,j-1);
		f[i][j]=min(ret1,ret2)+1;
	}
	return f[i][j];
}

int main()
{
	n=read();
	fo(i,1,n)fo(j,1,n)f[i][j]=inf;
	fo(i,1,n)s[i]=getchar();
	cout<<dfs(1,n)<<endl;
	return 0;
}


你可能感兴趣的:(dp)