zoukankan      html  css  js  c++  java
  • poj 3376 Finding Palindromes

    Finding Palindromes
    Time Limit: 10000MS   Memory Limit: 262144K
         
    Case Time Limit: 2000MS

    Description

    A word is called a palindrome if we read from right to left is as same as we read from left to right. For example, "dad", "eye" and "racecar" are all palindromes, but "odd", "see" and "orange" are not palindromes.

    Given n strings, you can generate n × n pairs of them and concatenate the pairs into single words. The task is to count how many of the so generated words are palindromes.

    Input

    The first line of input file contains the number of strings n. The following n lines describe each string:

    The i+1-th line contains the length of the i-th string li, then a single space and a string of li small letters of English alphabet.

    You can assume that the total length of all strings will not exceed 2,000,000. Two strings in different line may be the same.

    Output

    Print out only one integer, the number of palindromes.

    Sample Input

    3
    1 a
    2 ab
    2 ba
    

    Sample Output

    5

    Hint

    The 5 palindromes are: 
    aa aba aba abba baab 
     
    建立trie树
    用原串的反串在trie树上匹配
    假设反串匹配到i,trie树上到j
    1、如果j是单词节点,即以j结尾的单词是反串的前缀,那么如果i以后(反串剩余的部分,不包括i)是回文串,以j结尾的单词都可以与匹配的单词构成回文串
    2、如果反串匹配完了,即反串是以i结尾的单词的前缀,那么j后面(不包括j)有多少回文串,就可以产生多少合法答案
    关键:字符串的前缀回文和后缀回文
    用扩展kmp
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 2000008
    using namespace std;
    bool f[2][N];
    long long ans;
    char T[N],S[N];
    int len,tot,root,id;
    int st[N],ed[N],cnt;
    int nxt[N],expand[N];
    int trie[N][26],mark[N],sum[N];
    void getnxt(char *s,int ll,int rr)
    {
        int a=ll;
        nxt[0]=rr-ll+1;
        while(a+1<=rr && s[a]==s[a+1]) a++;
        nxt[1]=a-ll;
        a=1+ll;
        int p,l,j;
        for(int k=2+ll;k<=rr;k++)
        {
            p=a-ll+nxt[a-ll]-1; l=nxt[k-a];
            if(k-ll+l-1>=p)
            {
                j=p-k+ll+1>0 ? p-k+ll+1 : 0;
                while(k+j<=rr && s[k+j]==s[j+ll]) j++;
                nxt[k-ll]=j;
                a=k;
            }
            else nxt[k-ll]=l;
        }
    }
    void exkmp(char *s,char *t,int ll,int rr,int w)
    {
        getnxt(t,ll,rr);
        int a=ll;
        while(a<=rr && s[a]==t[a]) a++;
        expand[0]=a-ll;
        a=ll;
        int p,l,j;
        for(int k=ll+1;k<=rr;k++)
        {
            p=a-ll+expand[a-ll]-1; l=nxt[k-a];
            if(k-ll+l-1>=p)
            {
                j=p-k+ll+1>0 ? p-k+ll+1 : 0;
                while(k+j<=rr && s[k+j]==t[j+ll]) j++;
                expand[k-ll]=j;
                a=k;
            }
            else expand[k-ll]=l;
        }
        for(int i=ll-ll;i<=rr-ll;i++)
         if(i+expand[i]==rr-ll+1) f[w][i+ll]=true;
    }
    void insert(int ll,int rr)
    {
        root=0;
        for(int i=ll;i<=rr;i++)
        {
            id=S[i]-'a';
            sum[root]+=f[0][i];
            if(!trie[root][id]) trie[root][id]=++tot;
            root=trie[root][id];
        }
        mark[root]++;
    }
    void find(int ll,int rr)
    {
        root=0;
        for(int i=ll;i<=rr;i++)
        {
            id=T[i]-'a';
            root=trie[root][id];
            if(!root) return;
            if(i!=rr&&f[1][i+1] || i==rr) ans+=mark[root];
        }
         ans+=sum[root];
    }
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%s",&len,S+cnt);
            for(int j=0;j<len;j++) T[cnt+j]=S[cnt+len-j-1];
            st[i]=cnt;
            ed[i]=cnt+len-1;
            exkmp(S,T,st[i],ed[i],0);
            exkmp(T,S,st[i],ed[i],1);
            cnt+=len;
            insert(st[i],ed[i]);
        }
        for(int i=1;i<=n;i++)
         find(st[i],ed[i]);
        printf("%lld
    ",ans);
    }
  • 相关阅读:
    树莓派配置
    《C#微信开发系列(Top)-微信开发完整学习路线》
    Git基础使用教程(仓库初始化,源码clone,源码push)
    《Cron表达式详解》
    《CSS实现单行、多行文本溢出显示省略号》
    《C#多线程编程实现方式》
    《SQLServer删除重复数据的方法》
    《java提高数据导入效率优化思路》
    《如何使用Javascript判断浏览器终端设备》
    《动手实现一个网页加载进度loading》
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7050413.html
Copyright © 2011-2022 走看看