题目链接:传送门
题目大意;两只兔子,在n块围成一个环形的石头上跳跃,每块石头有一个权值ai,一只从左往右跳,一只从右往左跳,每跳一次,两只兔子所在的石头的权值都要相等,在一圈内(各自不能超过各自的起点,也不能再次回到起点)它们最多能经过多少个石头(1 <= n <= 1000, 1 <= ai <= 1000)。
题目思路:
两个方向跳跃,且每一步的值都相同,即求最长回文串子序列。
因为是一个环,所以我们可以把它拉长一条2*n的序列中的一段n长度的序列即可。
然后我们在考虑回文串的个数,我们发现可以是一个回文串,也可以是两个回文串的组合,三个及以上就不成立了。
那么我们先预处理回文串的dp,然后找到一个断点将区间分为左右两部分,将两部分各自最大的回文串相加即可。
//hdu 4745
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int maxn=4000;
int n;
int a[maxn];
int dp[maxn][maxn];
int ans[maxn];
int main()
{
while(~scanf("%d",&n)&&n)
{
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
a[i+n]=a[i];
dp[i][i]=dp[i+n][i+n]=1;
}
for(int i=1;i<n;i++)
{
for(int j=1;j+i<=2*n;j++)
{
dp[j][j+i]=max(dp[j+1][i+j],dp[j][i+j-1]);
if(a[j]==a[i+j])
{
dp[j][j+i]=max(dp[j][j+i],dp[j+1][j+i-1]+2);
}
}
}
memset(ans,0,sizeof ans);
for(int i=1;i<=n;i++)
{
int j=i+n-1;
ans[i]=dp[i][j];
for(int k=i;k<j;k++)
{
ans[i]=max(ans[i],dp[i][k]+dp[k+1][j]);
}
}
int cnt=0;
for(int i=1;i<=n;i++)cnt=max(cnt,ans[i]);
printf("%d\n",cnt);
}
return 0;
}