2017 HDU 6103 多校联合赛 Kirinriki

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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值