USACO theme

  这道题的意思是给你一个长度不超过5000的串, 让你求解一个主题串, 其中主题串的定义是在这个串中重复出现过两次,没有重叠部分, 且两个串各减某个数后序列一样。。我们可以定义dp[i][j]为从i位置和j位置开始相同的串的长度, dp[i][j] = dp[i+1][j+1] + 1; 其中num[j+1]-num[i+1] = num[j]-num[i], 另外求出这个答案后还要记得判断是否重叠, 最后答案也要加1, 代码如下:

/*
    ID: m1500293
    LANG: C++
    PROG: theme
*/

#include <cstdio>
#include <cstring>
#include <algorithm>


using namespace std;
int num[5000+10];
short dp[2][5010];   //dp[i][j]以i, j开始的最长相同子串

int main()
{
    freopen("theme.in", "r", stdin);
    freopen("theme.out", "w", stdout);
    int N;
    scanf("%d", &N);
    for(int i=1; i<=N; i++) scanf("%d", &num[i]);
    short res = 0;
    for(int i=N; i>=1; i--)
    {   memset(dp[i%2], 0, sizeof(dp[1]));
        for(int j=N; j>=1; j--)
        {

            if(j+1<=N && i+1<=N && num[j+1]-num[i+1]==num[j]-num[i]) dp[i%2][j] = dp[(i+1)%2][j+1] + 1;
            else dp[i%2][j] = 0;
            int x=j, y=j+dp[i%2][j]-1+1;
            if(!((i>=x&&i<=y)||(i+dp[i%2][j]-1+1>=x&&i+dp[i%2][j]-1+1<=y)))
                res = max(res, dp[i%2][j]);
        }
        //printf("
");
    }

    if(res+1>=5) printf("%d
", res+1);
    else printf("0
");
    return 0;
}
原文地址:https://www.cnblogs.com/xingxing1024/p/5176944.html