[kuangbin带你飞] Girls' research (最长回文子串)

Girls’ research

题目链接:专题十六 W - Girls’ research HDU - 3294

题意

给你一个字母和一个由小写字母构成的字符串,其中第一个字母代表着真实a的位置,例如给出’b’那么现在给出的字符串中的’b’都换成’a’,所有’c’都换成’b’……’a’换成’z’。第二个任务,就是要输出这其中的最长回文串的起始位置,和末尾,还要输出最长回文串。


思路

第一个问题挺简单的用个循环取模就行了,主要是第二个任务,就是要输出这其中的最长回文串的起始位置,和末尾,还要输出最长回文串,我的话经过探索,发现一个很好用的规律,就是在ntr数组中记录最长回文串的中心点,在依靠p[i]进行从左到右进行探索。


代码

#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = (int)(j);i <= (int)(k);i ++)
#define per(i,j,k) for(int i = (int)(j);i >= (int)(k);i --)
#define mmm(a,b)   memset(a,b,sizeof(a))
#define pb push_back

typedef long long ll;
const int INF = (int)0x3f3f3f3f;
const int MAXN = (int)4e5+7;

char ch[2];
char ptr[MAXN];
char ntr[MAXN];
int p[MAXN];
char chans[MAXN];
int len1,len2;
int pos;

void MakeNtr(){
    ntr[0] = '$';
    ntr[1] = '#';
    rep(i,0,len1-1){
        ntr[i*2+2] = ptr[i];
        ntr[i*2+3] = '#';
    }
    ntr[len2] = '\0';
}

int Manacher(){
    MakeNtr();
    int res = 0,id,mx = 0;
    rep(i,0,len2-1){
        if (i < mx) p[i] = min(p[id*2-i],mx-i);
        else        p[i] = 1;
        while (ntr[i+p[i]] == ntr[i-p[i]]) p[i] ++;
        if (mx < i+p[i]) {
            mx = i+p[i];
            id = i;
        }
        if (res < p[i]-1){
            res = p[i]-1;
            pos = i;
        }
    }
    return res;
}

int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

    while (cin >> ch >> ptr){
        len1 = strlen(ptr);
        len2 = len1*2+2;
        int ans = Manacher();
        if (ans >= 2) {
            int f1 = 0,f2 = 0,cnt = 0;
            rep(i,pos-ans+1,pos+ans-1){
                if (ntr[i] == '#') continue;
                if (i <= pos-ans+2) f1 = i/2-1;
                if (i >= pos+ans-2) f2 = i/2-1;
                chans[cnt++] = ((ntr[i]-ch[0]+26)%26+'a');
            }
            chans[cnt] = 0;
            cout << f1 << ' ' << f2 << endl;
            cout << chans << endl;
        }else {
            cout << "No solution!" << endl;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值