HDU 2017 多校联合训练赛6 1008 6103 Kirinriki 优美的暴力

Kirinriki

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)


Problem Description
We define the distance of two strings A and B with same length n is
disA,B=i=0n1|AiBn1i|
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
T100
0m5000
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
 

Source
2017 Multi-University Training Contest - Team 6



题目大意
定义两个长度相等的字符串a,b之间的距离 disA,B=i=0n1|AiBn1i| ,也就是说,将字符串b逆序处理,然后两个串对应字母的差累加和。现在给出一个字符串,和一个阈值m,要求找到该字符串中两条不重合的字符串a,b满足dis<=m,并且长度最长。


题目解析
题目有一点回文串的意思,如果两个不重合的子串从两端向中间延伸(在这里,左右两个子串的起点不一定从字符串的开头和结尾第一个字符开始,可能是第2,3...个,并且起点与两端的距离也不一定是相等的),我们最终可能会得到奇偶长度两种合串。,要找到长度最长的两条不重合的子串,题解给出了两种枚举方法。

第一种,也是标程的方法,枚举所有的中心。从中心开始,向两边延伸子串,双指针记录子串的头尾,如果两子串dis超过阈值m,那么同时抛掉两子串的尾字符,如果此时dis<=m,继续延伸,否则继续抛,直到一条子串到达字符串的一端。然后枚举下一个中心。
但是,这种方法要注意,两个不重合的子串从两端向中间延伸,可能会得到奇偶长度两种合串。所以为了遍历到所有子串,我们枚举的的中心位置也需要分奇偶,分为一个中心点和一对中心点两种情况。

个人觉得,分奇偶这种情况并不是很好考虑到,所以我用了第二种方法。
第二种,不需要考虑奇偶的问题,分别枚举了左右两端点的情况,注意两端点是分别枚举的,先假定右端点不动,枚举左端点,然后以左右端点为两子串的起点,像方法一,以同样的方法向中间延伸,超阈值就抛,知道两子串碰头。然后假设左端点不动,枚举右端点,同理。
至于为什么保持一端边界不动,只枚举另一端边界就能遍历到所有情况,我们可以结合方法一理解。方法一,子串从每一个中心延伸向外延伸,截止条件是一条子串碰到字符串的一端,也就是说,任意一个中心点都对应一对区间端点,并且区间端点至少有一个是字符串的边界。


方法一 代码(标程)
#include <iostream>
#include <cassert>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <ctime>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <string>
#include <bitset>
#include <vector>
#include <complex>
#include <algorithm>
using namespace std;

typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef vector<int> vi;
#define de(x) cout << #x << "=" << x << endl
#define rep(i,a,b) for(int i=a;i<(b);++i)
#define per(i,a,b) for(int i=(b)-1;i>=(a);--i)
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define fi first
#define se second

const int N = 1e4 + 10;
int T,m,n;
char s[N];

int main()
{
    scanf("%d",&T);
    rep(i,0,T)
    {
        scanf("%d%s",&m,s);
        int Mx=0;
        n=strlen(s);
        rep(i,0,n)
        {
            for(int l=i,r=i,pl=l,pr=r,dif=0; 0<=l&&r<n; ++r,--l)
            {
                dif+=abs((int)s[r]-s[l]);
                while(pr<=r&&dif>m)
                    dif-=abs((int)s[pr++]-s[pl--]);
                Mx=max(Mx,r-pr+(pr!=i));
            }
        }
        rep(i,1,n)
        {
            for(int l=i-1,r=i,pl=l,pr=r,dif=0; 0<=l&&r<n; ++r,--l)
            {
                dif+=abs((int)s[r]-s[l]);
                while(pr<=r&&dif>m)
                    dif-=abs((int)s[pr++]-s[pl--]);
                Mx=max(Mx,r-pr+1);
            }
        }
        printf("%d\n",Mx);
    }
    return 0;
}


方法二 代码
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
int T, m, n;//m:阈值;n:字符串长度
char s[5005];
int maxn, dif;
int L, R, l, r;
int i;

int main()
{
    scanf ("%d",&T);
    while (T--)
    {
        maxn = 0;
        memset (s, '\0', sizeof(s));
        scanf ("%d",&m);
        scanf ("%s",s);
        n = strlen(s);
        for (i=0; i<=n-2; ++i)
        {
            L = l = i;
            R = r = n-1;
            dif = 0;
            while (r-l >= 1)
            {
                dif += abs(s[r]-s[l]);
                while (L<=l && dif>m)
                    dif -= abs(s[R--]-s[L++]);
                maxn = max(maxn, l-L+1);
                l ++;
                r --;
            }
        }
        for (i=n-1; i>=1; --i)
        {
            L = l = 0;
            R = r = i;
            dif = 0;
            while (r-l >= 1)
            {
                dif += abs(s[r]-s[l]);
                while (L<=l && dif>m)
                    dif -= abs(s[R--]-s[L++]);
                maxn = max(maxn, l-L+1);
                l ++;
                r --;
            }
        }
        printf ("%d\n",maxn);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值