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("\n"); } if(res+1>=5) printf("%d\n", res+1); else printf("0\n"); return 0; }