hdu - 4745 - Two Rabbits(最长回文子序列)

题目链接:传送门

题目大意;两只兔子,在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;
}

猜你喜欢

转载自blog.csdn.net/qq_36782366/article/details/81513843