牛客每日一题3.26 合并回文子串 动态规划

首先这种题肯定是动态规划!!!!!不要往其他地方想。要怎么做呢先从单个串要怎么判断区间最长回文来说。单个串如果要判断任意一个区间[L,R]是不是回文可以去写区间dp,对于一个串长度大于2的回文串,如果要在此基础上在延长串的长度必然是在头尾加两个,所以对于一个串的就可以写出方程 f[L][R] |= F[L+1][R-1],(当a[L]==a[R]时);
现在到了两个串,其实思路差不多,两个串要拼出一个回文串也必然要在原先满足的基础上在加两个字母。那么我们这么设计状态
f[i][[j][x][y],代表A串使用了[i,j], B串使用了[x,y]能不能构成回文。
如果是在原先的回文串基础上增加两个字母,则哪个字母当头,哪个字母当尾,必然只有四种情况.
牛客每日一题3.26 合并回文子串 动态规划_第1张图片
解释一下第一个其他都是同理可得,当A串的i位置的字母等于B串j位置的字符,则我们可以看A的[i + 1, j -1]和B串的[x, y ]能不能构成回文,如果可以,则[i,j] [x,y]必然也是一个回文串。

这样子去枚举就可以啦,真的十分的暴力。复杂度是O(Tn*4)
其他注意的要点就是i和x要倒序枚举,因为你前面的状态需要后面的状态。还有就是当区间+1,-1后变成非法区间,就仅仅判断剩下那个合法区间是不是回文串就可以了!最后代码跑579ms还行。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define int long long
#define double long double
using namespace std;
#define PI  3.1415926535898
#define eqs 1e-17
const long long max_ = 50 + 2;
const int mod = 1e9 + 7;
const int inf = 1e9 + 7;
const long long INF = 1e18;
int read() {
	int s = 0, f = 1;
	char ch = getchar();
	while (ch<'0' || ch>'9') {
		if (ch == '-')
			f = -1;
		ch = getchar();
	}
	while (ch >= '0'&&ch <= '9') {
		s = s * 10 + ch - '0';
		ch = getchar();
	}
	return s * f;
}
inline void write(int x) {
	if (x < 0) {
		putchar('-');
		x = -x;
	}
	if (x > 9)
		write(x / 10);
	putchar(x % 10 + '0');
}
inline int min(int a, int b) {
	return a < b ? a : b;
}
inline int max(int a, int b) {
	return a > b ? a : b;
}
bool f[max_][max_][max_][max_];
int ans;
char a[max_], b[max_];
//00 01 10 11
// 0  1  2 3
int pana[max_][max_], panb[max_][max_],lena,lenb;
void solve() {
	for (int len = 1; len <= min(lena,2); len++) {
		for (int L = 1, R = len; R <= lena; L++, R++) {
			//[L,R]
			if (a[L] == a[R]) {
				pana[L][R] = 1;
			}
		}
	}
	for (int len = 3; len <= lena; len++) {
		for (int L = 1, R = len;  R <= lena; L++, R++) {
			//[L,R]
			if (a[L] == a[R]) {
				pana[L][R] |= pana[L + 1][R - 1];
			}
		}
	}

	for (int len = 1; len <= min(lenb, 2); len++) {
		for (int L = 1, R = len; R <= lenb; L++, R++) {
			//[L,R]
			if (b[L] == b[R]) {
				panb[L][R] = 1;
			}
		}
	}
	for (int len = 3; len <= lenb; len++) {
		for (int L = 1, R = len; R <= lenb; L++, R++) {
			//[L,R]
			if (b[L] == b[R]) {
				panb[L][R] |= panb[L + 1][R - 1];
			}
		}
	}
}
signed main() {
	int T;
	cin >> T;
	while (T--){
		cin >> a + 1 >> b + 1;
		 lena = strlen(a + 1), lenb = strlen(b + 1);
		ans = 1; 
		solve();
		for (int i = lena; i >= 1; i--) {
			for (int j = i; j <= lena; j++) {
				for (int x = lenb; x >= 1; x--) {
					for (int y = x; y <= lenb; y++) {
						if (a[i] == a[j] && i < j) {
							if (i + 1 <= j - 1) {//合法状态
								f[i][j][x][y] |= f[i + 1][j - 1][x][y];
							}
							else f[i][j][x][y] |= panb[x][y];
						}
						if (a[i] == b[y]) {
							if (i == j && x == y)f[i][j][x][y] = 1;//同时不合法
							if (i == j) {
								f[i][j][x][y] |= panb[x][y - 1];
							}
							if (x == y) {
								f[i][j][x][y] |= pana[i + 1][j];
							}
							f[i][j][x][y] |= f[i + 1][j][x][y - 1];
						}
						if (b[x] == a[j] ) {
							if (i == j && x == y)f[i][j][x][y] = 1;//同时不合法
							if (i == j) {
								f[i][j][x][y] |= panb[x + 1][y];
							}
							if (x == y) {
								f[i][j][x][y] |= pana[i][j - 1];
							}
							f[i][j][x][y] |= f[i][j - 1][x + 1][y];
						}
						if (b[x] == b[y] && x < y) {
							if (x + 1 <= y - 1) {
									f[i][j][x][y] |= f[i][j][x + 1][y - 1];
							}else 	f[i][j][x][y] |= pana[i][j];
						}
						if(f[i][j][x][y])
							ans = max(ans, (j - i + 1) + (y - x + 1));
					}
				}
			}
		}
		cout << ans << endl;
		memset(pana, 0, sizeof(pana));
		memset(panb, 0, sizeof(panb));
		memset(f, 0, sizeof(f));
	}
	return 0;
}

你可能感兴趣的:(区间dp)