题意:给定一个长度不超过5000的字符串s,求它的两个不重叠的长度都为(n)的连续子串(s1,s2),使得(dis(s1,s2)<=m).对于两个字符串(A,B),定义它们的距离(dis=sum_{i=1}^nabs(A_i-B_{n+1-i})).
分析:借鉴于马拉车算法的思想,我们把字符串S每个的字符之间插上一个隔板'|',便于我们不需要再讨论串的奇偶性.然后因为两个子串(s1,s2)是不重叠的,所以这两个子串肯定存在一个对称中心(要么是字母,要么是隔板),所以我们直接枚举这个对称中心,然后用尺取法,一点一点向外扩展,得到最大长度.
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=5005;
char ch[N],s[N*2];
int main(){
int T;scanf("%d",&T);
while(T--){
int m;scanf("%d%s",&m,ch+1);
int tot=strlen(ch+1),n=0;s[++n]='|';//第一个字符是隔板
for(int i=1;i<=tot;++i)
s[++n]=ch[i],s[++n]='|';//每读入一个字符,加一个隔板
int ans=0;
for(int i=1;i<=n;++i){
int l=0,r=0,now=0,x=i-1,y=i+1;
while(x-r>=1&&y+r<=n){//不越界
if(now+abs(s[x-r]-s[y+r])<=m){//能够向外扩展r就扩展r
ans=max(ans,(r-l+1)/2);//更新答案
now+=abs(s[x-r]-s[y+r]);
++r;
}
else{
now-=abs(s[x-l]-s[y+l]);//不能扩展r,就缩进l,保证能够扩展r
++l;
}
}
}
printf("%d
",ans);
}
return 0;
}