USACO1.3.3 Calf Flac 解题报告 (Manacher算法)

Description

据说如果你给无限只母牛和无限台巨型便携式电脑(有非常大的键盘),那么母牛们会制造出世上最棒的回文。你的工作就是去寻找这些牛制造的奇观(最棒的回文)。 在寻找回文时不用理睬那些标点符号、空格(但应该保留下来以便做为答案输出),只用考虑字母'A'-'Z'和'a'-'z'。要你寻找的最长的回文的文章是一个不超过20,000个字符的字符串。 我们将保证最长的回文不会超过2,000个字符(在除去标点符号、空格之前)。

Input

输入文件不会超过20,000字符。这个文件可能一行或多行,但是每行都不超过80个字符(不包括最后的换行符)。

Output

输出的第一行应该包括找到的最长的回文的长度。 下一行或几行应该包括这个回文的原文(没有除去标点符号、空格),把这个回文输出到一行或多行(如果回文中包括换行符)。 如果有多个回文长度都等于最大值,输出最前面出现的那一个。

Sample Input

Confucius say: Madam, I'm Adam.

Sample Output

11
Madam, I'm Adam

 

不区分大小写,不看非字母,让求最长回文串并输出其中所有内容

 

首先将字符串处大写变成小写,去掉非字母字符映射到另外一个串里(记录好两个串相同字母对应的下标,方便回溯).然后对另外一个串套用Manacher即可,最后再将最长回文串的起点字母和终点字母之间的内容全部输出即可

 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define lowbit(a) (a&(-a))
#define _mid(a,b) ((a+b)/2)
#define _mem(a,b) memset(a,0,(b+3)<<2)
#define fori(a) for(int i=0;i='A'&&c<='Z')||(c>='a'&&c<='z');}
char func(char c){return (c>='A'&&c<='Z')?c+32:c;}
int Manacher(char s[],int len) {
    int l = 0;
    bufs[l++] = '$';
    bufs[l++] = '#';
    for (int i = 0; i < len; i++) {
        bufs[l++] = s[i];
        bufs[l++] = '#';
    }
    bufs[l] = 0;
    int MaxR = 0;
    int flag = 0;
    for (int i = 0; i < l; i++) {
        cntm[i] = MaxR > i ? min(cntm[2 * flag - i], MaxR - i) : 1;
        while (bufs[i + cntm[i]] == bufs[i - cntm[i]])
            cntm[i]++;
        if (i + cntm[i] > MaxR) {
            MaxR = i + cntm[i];
            flag = i;
        }
      }
    MaxR = 0;
    for(int i=1;i<=len*2+2;i++)
    {
        if(MaxR < cntm[i]-1){
            MaxR = cntm[i]-1;
            flag = i/2-1;
        }
    }
    e = flag;
    return MaxR;
}
int main(){
    int cnt = 0;
    char buf;
    while((buf=getchar())!=EOF)
        c[cnt++] = buf;
    int cntb = 0;
    fori(cnt){            //将c中的内容映射到b中去,且将对应下标存入q中
        if(juge(c[i])){
            q[cntb] = i;
            b[cntb++] = func(c[i]);
        }
    }
    int res = Manacher(b,strlen(b));
    cout << res << endl;
    int first = q[e-(res-1)/2];    //起点为终点-(中心点-1)/2
    while(res--&&c[first]){        //输出原串
        if(!juge(c[first]))
            res++;
        cout << c[first++];
    }
    cout <

 

你可能感兴趣的:(USACO训练题集,字符串)