Problem
acm.hdu.edu.cn/showproblem.php?pid=6103
Meaning
两个长为 n 的字符串 A、B,定义
disA,B=∑n−1i=0|Ai−Bn−1−i|
。
给定一个字符串 S 和整数 m,在 S 中找两个尽量长的不相交的子串 A、B,满足
disA,B<m
,求长度。
Analysis
任意两个不相交子串,都可以看作处于以某个位置为中心的对称位置上。
枚举这个中心(奇数中心 L = R,偶数中心 L + 1 = R),然后同时向两边尽量拓展,记录下每个拓展长度(记为 x)处的
|s[L−x]−s[R+x]|
,再在这段拓展的长度上进行尺取、更新答案。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int S = 5000;
char s[S+2];
int t[S+2] = {0};
int odd(int len, int m)
{
int res = 0;
// L = R = p
for(int p = 1; p < len - 1; ++p)
{
int x = 1;
for( ; p >= x && p < len - x; ++x)
t[x] = abs(s[p - x] - s[p + x]);
int tmp = 0, cnt = 0;
for(int l = 1, r = 1; l < x; )
{
if(l == r)
cnt += t[r++];
while(r < x && cnt + t[r] <= m)
cnt += t[r++];
if(cnt <= m && r - l > tmp)
tmp = r - l;
if(r >= x)
break;
cnt -= t[l++];
}
if(tmp > res)
res = tmp;
}
return res;
}
int even(int len, int m)
{
int res = 0;
// R = L + 1
for(int l = 0; l < len - 1; ++l)
{
int x = 0;
for(int r = l + 1; l >= x && r < len - x; ++x)
t[x] = abs(s[l - x] - s[r + x]);
int tmp = 0, cnt = 0;
for(int l = 0, r = 0; l < x; )
{
if(l == r)
cnt += t[r++];
while(r < x && cnt + t[r] <= m)
cnt += t[r++];
if(cnt <= m && r - l > tmp)
tmp = r - l;
if(r >= x)
break;
cnt -= t[l++];
}
if(tmp > res)
res = tmp;
}
return res;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int m;
scanf("%d %s", &m, s);
int len = strlen(s), ans = 0;
// 奇数中心 -> 以某个字符为中心
ans = max(ans, odd(len, m));
// 偶数中心 -> 以相邻字符的“中间”为中心
ans = max(ans, even(len, m));
printf("%d\n", ans);
}
return 0;
}