HDU 6103 Kirinriki (尺取)

Description

定义两个长度同为\(n\)的字符串A和B之间的距离为

\[dis(A,B)=\sum_{i=0}^{n-1}{A_i-B_{n-1-i}} \]

给出一个字符串S,请你求出S的两个长度不超过\(m\)且不重叠子串的最大长度。

Input

第一行给出用例组数\(T\),对于每组测试用例,第一行给出\(m\),第二行给出字符串S。\(T \leqslant 100\)\(0 \leqslant m \leqslant 5000\)\(2 \leqslant |S| \leqslant 5000\)

Output

对于每组用例,输出一个整数,表示字串的最大长度。

Sample Input

1
5
abcdefedcb

Sample Output

5

Solution

简单分析可知,最终答案的形式一定是A串和B串之间有一条对称轴,从对称轴向两边延伸,A串和B串中对应位置字符的差的绝对值求和不超过\(m\),而此时的A,B串长度最长。

对称轴有两种,一种以字符为对称轴,一种以字符之间的间隔为对称轴,分别枚举这两种对称轴。一旦对称轴确定,两侧对应字符对也随之确定,此时问题转化为给出一段序列,求和不大于\(m\)的最长序列的长度。典型的尺取问题。

给出上限限制k,依次推进左端点,对于每个左端点,向右移动右端点直到第一个不合法的位置,此时区间长度减一即为当前左端点对应的答案。随着左端点的推进,会出现右端点直到最右端也不会不合法的情况,此时的区间长度就是当前左端点的答案。因为此后区间不会更长,更新后跳出即可。

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 5e3 + 10;

char s[N];

int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		int m;
		scanf("%d%s", &m, s);
		int len = strlen(s);
		int ans = 0;
		for (int mid = 1; mid <= len - 2; mid++)
		{
			int lb = mid + 1;
			int ub = lb + min(mid, len - mid - 1);
			for (int l = lb, r = lb, sum = 0; l < ub; l++)
			{
				while (r < ub && sum <= m) sum += abs(s[r] - s[2 * mid - r]), r++;
				if (sum <= m) {	ans = max(ans, r - l); break; }
				ans = max(ans, r - l - 1);
				sum -= abs(s[l] - s[2 * mid - l]);
			}
		}
		for (int mid = 1; mid <= len - 1; mid++)
		{
			int lb = mid;
			int ub = lb + min(mid, len - mid);
			for (int l = lb, r = lb, sum = 0; l < ub; l++)
			{
				while (r < ub && sum <= m) sum += abs(s[r] - s[2 * mid - 1 - r]), r++;
				if (sum <= m) { ans = max(ans, r - l); break; }
				ans = max(ans, r - l - 1);
				sum -= abs(s[l] - s[2 * mid - 1 - l]);
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

http://acm.hdu.edu.cn/showproblem.php?pid=6103

posted @ 2017-08-11 17:19  达达Mr_X  阅读(244)  评论(0)    收藏  举报