poj3376 KMP+字典树求回文串数量(n*n)

Finding Palindromes

Time Limit: 10000MS   Memory Limit: 262144K
Total Submissions: 4043   Accepted: 746
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

http://blog.csdn.net/acblacktea/article/details/51884850  //转载这篇博客

#include<cstdio>
#include<cstring>
#include<vector>
typedef long long LL;
using namespace std;
const int N=2000005;
struct node{
    int sum,son[26],cnt;
}no[N];
struct str{
    int start,en;
    str(int s,int e):start(s),en(e){};
    str(){};
};
vector<str>ve;
int fla[N][2],nexta[N],tot=0,n,pre,l;
char s[N],t[N];
void getNext(char *a,int la){
    int i=0,j=-1;
    nexta[0]=-1;
    while(i<la){
        if(j==-1||a[i]==a[j]) nexta[++i]=++j;
        else j=nexta[j];
    }
}
void kmp(int flag,char *a,char *b,int la,int start){
    int i=0,j=0;
    while(i<la){
        if(j==-1||a[j]==b[i]) ++i,++j;
        else j=nexta[j];
    }
    int pre=j;
    if(!flag) {
        while(pre){
            fla[start+pre-1][0]=1;
            pre=nexta[pre];
        }
    }
    else {
        while(pre){
            fla[start+l-pre][1]=1;
            pre=nexta[pre];
        }
    }
}
void insertTire(int pre,char *a,int start,int la)//储存前缀
{
     for(int i=0;i<l;i++)
     {
         if(!no[pre].son[a[i]-‘a‘])
         {
             tot++;
             no[pre].son[a[i]-‘a‘] = tot;
             pre = tot;
         }
         else pre = no[pre].son[a[i]-‘a‘];
         if(i+1<la)no[pre].cnt+=fla[start+i+1][1];
     }
     no[pre].sum++;
}
LL findTrie(int start,int en,int pre){
    int sym=true;
    LL ans=0;
    int l=en-start;
    for(int i=start;i<en;++i) {
        if(no[pre].son[t[i]-‘a‘]) {
            pre=no[pre].son[t[i]-‘a‘];
            if(fla[start+l-(i-start+1)-1][0]||i==en-1) ans+=no[pre].sum;
        }
        else {
            sym=0;break;
        }
    }
    if(sym) ans+=no[pre].cnt;
    return ans;
}
int main(){
    pre=0;
    LL ans=0;
    for(scanf("%d",&n);n--;){
        scanf("%d %s",&l,s+pre);
        ve.push_back(str(pre,pre+l));
        for(int i=pre;i<pre+l;++i) t[i]=s[pre+l-(i-pre+1)];
        getNext(s+pre,l);
        kmp(0,s+pre,t+pre,l,pre);
        getNext(t+pre,l);
        kmp(1,t+pre,s+pre,l,pre);
        insertTire(0,s+pre,pre,l);
        pre+=l;
    }
    for(int i=0;i<(int)ve.size();++i) ans+=findTrie(ve[i].start,ve[i].en,0);
    printf("%I64d\n",ans);
}
时间: 2024-11-08 18:28:20

poj3376 KMP+字典树求回文串数量(n*n)的相关文章

马拉车,O(n)求回文串

body { font-family: sans-serif; font-size: 14px; line-height: 1.6; padding-top: 10px; padding-bottom: 10px; background-color: white; padding: 30px } body>*:first-child { margin-top: 0 !important } body>*:last-child { margin-bottom: 0 !important } a

Palindrome - URAL - 1297(求回文串)

题目大意:RT 分析:后缀数组求回文串,不得不说确实比较麻烦,尤其是再用线段数进行查询,需要注意的细节地方比较多,比赛实用性不高......不过练练手还是可以的. 线段数+后缀数组代码如下: =========================================================================================================================================== #include<stdio

HDU 5371(2015多校7)-Hotaru&#39;s problem(Manacher算法求回文串)

题目地址:HDU 5371 题意:给你一个具有n个元素的整数序列,问你是否存在这样一个子序列,该子序列分为三部分,第一部分与第三部分相同,第一部分与第二部分对称,如果存在求最长的符合这种条件的序列. 思路:用Manacher算法来处理回文串的长度,记录下以每一个-1(Manacher算法的插入)为中心的最大回文串的长度.然后从最大的开始穷举,只要p[i]-1即能得出以数字为中心的最大回文串的长度,然后找到右边对应的'-1',判断p[i]是不是大于所穷举的长度,如果当前的满足三段,那么就跳出,继续

求回文串个数

先整理各路大神的题解 Orz,以后再埋坑 SP7586 NUMOFPAL - Number of Palindromes Description 求一个串中包含几个回文串. Input 输入一个字符串S Output 包含的回文串的个数. 思路一: 用马拉车求出预处理后以每个字母处的回文半径P[i],遍历一遍,ans=ans+P[i]/2,最终ans就是答案 答案是以每一位为中心的回文串长度/2的和,(如果添加字符则为回文半径长度/2.) 不能理解的话,可以看下这个 # a # a # b #

[haoi2009]求回文串

所谓回文串,就是对于给定的字符串,正着读和反着读都一样,比如ABCBA就是一个回文串,ABCAB则不是.我们的目标是对于任意输入的字符串,不断将第i个字符和第i+1个字符交换,使得该串最终变为回文串.求最少交换次数. 题解: 有一种做法是贪心: 就是每次找到最左端的字符,然后找到这序列中最右边的一样的字符,然后把这个字符移过去,然后把最左端右移,继续以上操作: 最后的答案就是每次的移动步数加起来: 要吐槽的是,window下I64d不要忘了...... #include<iostream> #

Codeforces Round #427 (Div. 2) D. Palindromic characteristics(Manacher求回文串)

题目链接:Codeforces Round #427 (Div. 2) D. Palindromic characteristics 题意: 给你一个串,定义k-th回文串,让你求每个k-th的数量. 题解: manacher处理好后做一下dp就行了. 当然也可以直接dp不用manacher. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace std; 4 5 cons

HDU 1513 Palindrome 求回文串

这个题是走弯路了,刚开始自己DP出了方程,无限MLE,唉 if(s1[i]==s1[j]) dp[i][j]=dp[i+1][j-1]; else dp[i][j]=min(dp[i][j-1],dp[i+1][j]) +1; 后来百度了一下,这个原来是个经典回文串问题,即先将串置反,然后求LCS........ 然后就是这题卡时间卡的特别厉害,多用了一次strlen就TLE AC: #include<cstdio> #include<string> #include<str

hihocoder 1032 manachar 求回文串O(n)

#include <cstdio> #include <iostream> #include <algorithm> #include <queue> #include <cmath> #include <cstring> #include <stack> #include <set> #include <map> #include <vector> using namespace st

hdu 3294 manacher 求回文串

感谢: http://blog.csdn.net/ggggiqnypgjg/article/details/6645824/ O(n)求给定字符串的以每个位置为中心的回文串长度. 中心思想:每次计算位置i的答案时,利用已经算出的1~i-1位置的答案. 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #define maxn 222222 5 using namespace std; 6 7