首页 > 技术文章 > 回文检测题解

GDOI2018 2019-01-04 14:16 原文


题目右转luogu1210

我看到这道题的第一想法是枚举答案 (长度)

但是很显然会超时,怎样优化枚举是关键

我想到了二分答案。但是二分答案要求答案具有单调性。

乍一看,似乎回文子串没什么单调性。但是如果我们将答案分为奇偶两种,答案的单调性就出来了

1.当最长回文串长度是奇数时:

不妨假设长度为\(9\),那么我们就会发现,\(9\)以下的奇数长度 (1,3,5,7) 都是存在回文串的,奇数的单调性我们找到了

2.当回文串为偶数时
同理,设长度为\(6\)\(6\)以下的偶数长度 (2,4) 也都是可以的。

然后我们就可以开始二分了

相信写程序对各位DALAO不是问题,上代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=20005;
string s,t;int len1;
int begin,end;
int ans;
struct node
{
    char S;
    int start;
}st[maxn];
bool ok(int x,int y)
{
    int rt=x,lt=y;
    while(rt<=lt)
    {
        if(st[rt].S!=st[lt].S) return false;
        rt++,lt--; 
    }
    return true;
}
bool add(int x)
{
    int head=1,tail=x;
    while(tail<=len1)
    {
        if(ok(head,tail))
        {
           begin=st[head].start;
           end=st[tail].start;
           return true;
        }
        head++,tail++;
    }
    return false;
}
int main()
{
    while(getline(cin,t))//注意读入数据的处理 
    {
        s+=t+'\n';
    };
    s=' '+s;
    int len=s.size()-1;
    for(int i=1;i<=len;i++)
    {
        if(s[i]>='A'&&s[i]<='Z') st[++len1].S=s[i]-'A'+'a',st[len1].start=i;//改小写 
        else if(s[i]>='a'&&s[i]<='z') st[++len1].S=s[i],st[len1].start=i; 
    }
    int lt=0,rt;
    if(len1%2==0) rt=len1;
    else rt=len1+1;
    while(lt+2<rt)//二分奇数  特别注意 lt+2 
    {
        int mid=(lt+rt)/2;
        if(mid%2==0) mid++;
        if(add(mid)) lt=mid;
        else rt=mid;
    }
    int b=begin,e=end;
    ans=lt;
    lt=1;
    if(len1%2==0) rt=len1+1;
    else rt=len1;
    while(lt+2<rt)//二分偶数  
    {
        int mid=(lt+rt)/2;
        if(mid%2==1) mid++;
        if(add(mid)) lt=mid;
        else rt=mid;
    }
    if(ans>lt)//比较大小 
    {
        cout<<ans<<endl;
        for(int i=b;i<=e;i++)
           cout<<s[i];
    }
    else 
    {
        cout<<lt<<endl;
        for(int i=begin;i<=end;i++)
           cout<<s[i];
    }
    return 0;
}

推荐阅读