题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4681
题意:给你字符串A,B,C,让你找一个字符串D,使得D串是A,B的子序列,而C串是D的子串
思路:先预处理正,逆向的最长公共子序列及C在A,B中的位置,然后对于每一个位置对,即可知D的长度为前一半的LCS + C长度 + 后一半的LCS
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <functional>
#include <utility>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <set>
#include <cmath>
#include <stdlib.h>
#include <climits>
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#pragma comment (linker, "/STACK:1024000000,1024000000")
typedef long long ll;
using namespace std;
const int maxn = 1010;
char a[maxn], b[maxn], c[maxn];
int dp1[maxn][maxn], dp2[maxn][maxn];
int s1[maxn][2], s2[maxn][2];
void reverse(char *s)
{
int len = strlen(s);
for (int i = 0; i < len / 2; i++)
swap(s[i], s[len - 1 - i]);
}
void lcs(char *s1, char *s2, int dp[maxn][maxn])
{
int l1 = strlen(s1), l2 = strlen(s2);
memset(dp, 0, sizeof(dp));
for (int i = 0; i < l1; i++)
{
for (int j = 0; j < l2; j++)
{
if (s1[i] == s2[j])
dp[i + 1][j + 1] = dp[i][j] + 1;
else
dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j]);
}
}
// cout << dp[l1][l2] << endl;
}
int str(char *s1, char *s2, int s[maxn][2])
{
int l1 = strlen(s1), l2 = strlen(s2);
int n = 0;
for (int i = 0; i < l1; i++)
{
if (s1[i] == s2[0])
{
int k = 1, j;
for (j = i + 1; j < l1; j++)
{
if (s1[j] == s2[k])
k++;
if (k == l2) break;
}
if (k == l2)
{
s[n][0] = i;
s[n++][1] = j;
}
}
}
return n;
}
int main()
{
int t;
scanf("%d", &t);
for (int ca = 1; ca <= t; ca++)
{
scanf("%s%s%s", a, b, c);
int la = strlen(a), lb = strlen(b), lc = strlen(c);
int n1 = str(a, c, s1);
int n2 = str(b, c, s2);
lcs(a, b, dp1);
reverse(a);
reverse(b);
lcs(a, b, dp2);
int ans = 0;
for (int i = 0; i < n1; i++)
{
for (int j = 0; j < n2; j++)
{
ans = max(ans, lc + dp1[s1[i][0]][s2[j][0]] + dp2[la - 1 - s1[i][1]][lb - 1 - s2[j][1]]);
}
}
printf("Case #%d: %d\n", ca, ans);
}
return 0;
}