Finding Palindromes POJ - 3376(两个字符拼接为回文串,字典树+马拉车)

题目链接

题意:n个字符串,两两拼接能最多形成多少种,自己可以和自己拼接。

思路:设a,b两个串要拼接判断其是否为回文串分三种情况考虑:

第一种:alen < blen a是b的反串前缀,且b的剩余部分可以认为是后缀是回文串

第二种:alen > blen b的反串是a的前缀,且a的后缀是回文串

第三种:alen == blen a就是b反串。

根据上面的三种情况我们要求出字符串是否为另一个前缀,还有就是其后缀是否为回文串。所以可以想到马拉车算法和字典树。正串建立字典树,反串去进行匹配。

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<map>
#include<algorithm>
#define N 200060
#define ll long long
using namespace std;
const int maxn=2000110;
char a[maxn],text[maxn*2];
int P[maxn*2];
int trie[maxn][28],End[maxn],hou[maxn];
int n,root,ans,idx;
struct point
{
    int len;
    int st;
}b[maxn];
void pre_treat(){
    int len = strlen(a);
    for(int i=0;i<len;i++){
        text[i*2] = '#';
        text[i*2+1] = a[i];
    }
    text[len*2]='#';text[len*2+1]='\0';
}
void manacher(){
    P[0] = 1;                                   //第一个字符的回文串肯定是1
    int len = strlen(text);
    int md = 0;
    for(int i=1;i<len;i++){
        if(i<md+P[md]){
            int k = P[md*2-i];                  //找到对称点的回文串长度
            if(i+k<md+P[md]) P[i] = k;          //回文串没有超过右界
            else{
                k = md+P[md]-i;
                while(i+k<len&&i+k>=0&&text[i+k]==text[i-k]) k++;
                md = i;
                P[i] = k;
            }
        }
        else{
            int k = 1;
            while(i+k<len&&i+k>=0&&text[i+k]==text[i-k]) k++;
            md = i;
            P[i] = k;
        }
    }
}

void Insert()
{
//    printf("%s\n",text);
    for(int i=0;i<n;i++)
    {
        int now=root;
        for(int j=b[i].st;j<b[i].st+b[i].len;j++){
            if(!trie[now][a[j]-'a']) trie[now][a[j]-'a']=++idx;
            now=trie[now][a[j]-'a'];
            int mid=((j)*2-1+(b[i].st+b[i].len-1)*2+1)/2;
            if(P[mid]>mid-(j+2)*2+2)
                hou[now]++;
        }
        hou[now]--;
                                           
        End[now]++;
    }
}
void Find()
{
    for(int i=0;i<n;i++)
    {
        int now=root;
        for(int j=b[i].st+b[i].len-1;j>=b[i].st;j--)
        {
        //    printf("j:%d\n",j);
            if(!trie[now][a[j]-'a']){
                now=-1;
                break;
            }
            now=trie[now][a[j]-'a'];
            if(End[now])
            {
                int mid=(b[i].st*2-1+(j)*2+1)/2;
                //printf("mid:%d %d\n",P[mid],mid-b[i].st*2+1-2+1);
                if(P[mid]>mid-b[i].st*2){
                    ans+=End[now];
                  //  printf("End:%d\n",End[now]);
                }
            }
        }
        if(now!=-1){ans+=hou[now];
      //  printf("hou:%d\n",hou[now]);
    }
    }
}

int main()
{
    while(~scanf("%d",&n))
    {
        memset(trie,0,sizeof(trie));
        memset(hou,0,sizeof(hou));
        memset(End,0,sizeof(End));
        int len1=0;
        root=0,ans=0,idx=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&b[i].len);
            scanf("%s",a+len1);
            b[i].st=len1;
            len1+=b[i].len;
        }
        pre_treat();
        manacher();
        Insert();
        Find();
        printf("%d\n",ans);
    }
 } 

 

posted @ 2020-09-14 21:31  Ldler  Views(102)  Comments(0Edit  收藏  举报