We define the distance of two strings A and B with same length n is
dis(A,B)= ∑ (i=0→n−1) abs (Ai−Bn−1−i)
The difference between the two characters is defined as the difference in ASCII.
You should find the maximum length of two non-overlapping substrings in given string S, and the
distance between them are less then or equal to m.
Input
The first line of the input gives the number of test cases T; T test cases follow.
Each case begins with one line with one integers m : the limit distance of substring.
Then a string S follow.
Limits
T≤100
0≤m≤50000
Each character in the string is lowercase letter, 2≤|S|≤5000
∑|S|≤20000
Output
For each test case output one interge denotes the answer : the maximum length of the substring.
Sample Input
1
5
abcdefedcb
Sample Output
5
Hint
[0, 4] abcde
[5, 9] fedcb
The distance between them is abs(‘a’ - ‘b’) + abs(‘b’ - ‘c’) + abs(‘c’ - ‘d’) + abs(‘d’ - ‘e’) + abs(‘e’ - ‘f’) = 5
题意:
给出一个m和一串字符串。
要求从中找到两个没有重合部分的各自连续字符串a[ ],b[ ],然后反转b[ ],求(a[1]-b[1])+(a[2]-b[2])+
……+(a[n]-b[n]) <=m,求出满足此条件的最大长度n。
思路:
题解给出了两种思路。
第一种是枚举中间点,然后向两边扩展,遍历完每组区间。
因为如果把任何两个区间同步向中间移动,都会找到唯一确定的一个(或一对)中间点。所以如果枚举中间点
的话,可以把每一对区间都遍历。但是这里有一个需要注意的地方,那就是一对区间是同步移动的,所以他
们中间距离的奇偶性是不会发生改变的,所以需要讨论两种情况,一种是以一个中心点开始往两边扩展的,
另一种是以一对中心点向两边扩展的。
第二种是枚举两个边界,然后向中间压缩,遍历完每组区间。
因为如果把任何两个区间同步向外移动,当其中一端碰到边界时,都会找到唯一确定的一对边界点。所以如
果枚举边界点的话,可以把每一对区间都遍历。但是这里也有一个需要注意的地方,那就是一对区间是同步
移动的,所以他们谁先碰到边界是不一定的,所以需要讨论两种情况,一种是左边先碰到边界,另一种是右
边先碰到边界。
第一种思路,枚举中间点:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
const int N = 1e4 + 10;
int T,m,len,maxn,pr,pl,sum;
char ss[N];
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%ss",&m,ss);
maxn=0;
len=strlen(ss);
for(int i=len-1; i>=0; i--)
{
pl=pr=i;
sum=0;
for(int l=i,r=i; 0<=l&&r<len; r++,l--)
{
sum+=abs(ss[r]-ss[l]);
while(pr<=r&&sum>m)
{
sum-=abs(ss[pr++]-ss[pl--]);
}
maxn=max(maxn,r-pr+(pr!=i));
}
}
for(int i=1; i<len; i++)
{
pl=i-1;
pr=i;
sum=0;
for(int l=i-1,r=i; 0<=l&&r<len; r++,l--)
{
sum+=abs(ss[r]-ss[l]);
while(pr<=r&&sum>m)
{
sum-=abs(ss[pr++]-ss[pl--]);
}
maxn=max(maxn,r-pr+1);
}
}
printf("%d\n",maxn);
}
return 0;
}
第二种思路,枚举两个边界点:
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int t,m,Maxlen,n,lef,rig,sum;
char ss[5000+5];
int main()
{
scanf("%d",&t);
while(t--)
{
memset(ss,'\0',sizeof(ss));
scanf("%d",&m);
scanf("%s",ss);
n=strlen(ss);
Maxlen=0;
for(int i=0;i<n-1;i++)
{
lef=i;
rig=n-1;
sum=0;
for(int l=i,r=n-1; l<r ;l++,r--)
{
sum+=abs(ss[l]-ss[r]);
while(lef<=l&&sum>m)
{
sum-=abs(ss[lef++]-ss[rig--]);
}
Maxlen=max(Maxlen,l-lef+1);
}
}
for(int i=n-1;i>0;i--)
{
lef=0;
rig=i;
sum=0;
for(int r=i,l=0; l<r ;l++,r--)
{
sum+=abs(ss[l]-ss[r]);
while(lef<=l&&sum>m)
{
sum-=abs(ss[lef++]-ss[rig--]);
}
Maxlen=max(Maxlen,l-lef+1);
}
}
printf("%d\n",Maxlen);
}
return 0;
}