Finding Palindromes
Time Limit: 10000MS   Memory Limit: 262144K
Total Submissions:4710   Accepted: 879
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 

Source

POJ Monthly--2007.09.09, Zhou Gelin, modified from POI06
 
题意:
给定n个字符串。问把他们两两组合起来,能有多少个回文串。
思路:
两个字符串$s,t$进行组合有三种情况。
1、$lens=lent$,若$s$和$t$对称,那么可以$st$是一个回文串。
2、$lens>lent$,若$t$和$s$的前缀对称,$s$剩余的部分是一个回文,那么$st$是一个回文串。
3、$lens<lent$,若$s$和$t$的前缀对称,$t$剩余的部分是一个回文,那么$ts$是一个回文串。
现在我们对所有字符串建立一个字典树,然后用每一个反向串在树上进行匹配。
对于第一种可能,很简单,反向串匹配完的那个节点,是$cnt$个字符串的结尾,$ans+=cnt$
对于第二种可能,反向串不能继续匹配了之后,如果剩余的串是是回文,那么也是$ans += cnt$
对于第三种可能,反向串匹配到结尾之后,如果树上这个节点之后有$val$个回文,那么$ans+=val$
因此我们现在需要在Trie树上维护两个值,$cnt$和$val$
 
exKMP我们可以求出某个点之后是不是回文串。
将$s$作为模式串,与反向串$s'$进行exkmp。若$ex[i] = len - i + 1$,那么$s'[i...len]$是一个回文串。
同理将$s'$作为模式串,与$s$进行exkmp。
由此可以在建立Trie树时确定$cnt$和$val$
 
由于题目没有说$n$的范围,只给定了字符串的总长。所以我们只能把所有字符串都存在同一个字符串中,用数组记录开始和结束下标。
 
 #include<iostream>
//#include<bits/stdc++.h>
#include<cstdio>
#include<cmath>
//#include<cstdlib>
#include<cstring>
#include<algorithm>
//#include<queue>
#include<vector>
//#include<set>
//#include<climits>
//#include<map>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
#define N 100010
#define pi 3.1415926535
#define inf 0x3f3f3f3f const int maxn = 2e6 + ;
int n, sum_len;
char s[maxn], s_rev[maxn];
int st[maxn], ed[maxn]; int nxt[maxn], ex[maxn];
bool flag[][maxn];
void GETNEXT(char *str, int l, int r)
{
int i=l,j,po;
nxt[i]=r - l + ;//初始化next[0]
while(str[i]==str[i+]&&i<=r)//计算next[1]
i++;
nxt[l + ]=i - l;
po= + l;//初始化po的位置
for(i=+l;i<=r;i++)
{
if(nxt[i-po + l]+i - l<nxt[po]+po - l)//第一种情况,可以直接得到next[i]的值
nxt[i]=nxt[i-po + l];
else//第二种情况,要继续匹配才能得到next[i]的值
{
j=nxt[po]+po-i;
if(j<)j=;//如果i>po+next[po],则要从头开始匹配
while(i+j<=r&&str[l+j]==str[j+i])//计算next[i]
j++;
nxt[i]=j;
po=i;//更新po的位置
}
}
}
//计算extend数组
void EXKMP(char *s1,char *s2, int l, int r, int sign)
{
int i=l,j,po;
GETNEXT(s2, l, r);//计算子串的next数组
//for(j = l; j <= r; j++)cout<<nxt[j]<<endl;
while(s1[i]==s2[i]&&i<=r)//计算ex[0]
i++;
ex[l]=i - l;
po=l;//初始化po的位置
for(i=l + ;i<=r;i++)
{
if(nxt[i-po + l]+i - l<ex[po]+po -l)//第一种情况,直接可以得到ex[i]的值
ex[i]=nxt[i-po+l];
else//第二种情况,要继续匹配才能得到ex[i]的值
{
j=ex[po]+po-i;
if(j<)j=;//如果i>ex[po]+po则要从头开始匹配
while(i+j<=r&&s1[j+i]==s2[l+j])//计算ex[i]
j++;
ex[i]=j;
po=i;//更新po的位置
}
}
for(int i = l; i <= r; i++){
//cout<<ex[i]<<endl;
if(ex[i] == r - i + ){
flag[sign][i] = true;
}
}
} struct Trie{
int trie[maxn][];
int cnt[maxn];
int val[maxn];
int tot;
}tr; void init()
{
memset(flag, , sizeof(flag));
memset(nxt, , sizeof(nxt));
memset(ex, , sizeof(ex));
for(int i = ; i <= tr.tot; i++){
memset(tr.trie[i], , sizeof(tr.trie[i]));
tr.cnt[i] = ;
tr.val[i] = ;
}
tr.tot = ;
} void insertt(char *str, int l, int r)
{
int p = ;
for(int k = l; k <= r; k++){
int ch = str[k] - 'a';
tr.val[p] += flag[][k];
if(tr.trie[p][ch] == ){
tr.trie[p][ch] = ++tr.tot;
}
p = tr.trie[p][ch]; }
tr.cnt[p]++;
} LL searchh(char *str, int l, int r)
{
LL ans = ;
int p = ;
for(int k = l; k <= r; k++){
//cout<<flag[k]<<endl;
int ch = str[k] - 'a';
p = tr.trie[p][ch];
if(p == )break;
if(k < r && flag[][k + ] || k == r)ans += tr.cnt[p];
}
if(p)ans += tr.val[p];
//ans += tr.cnt[p];
return ans;
} int main()
{
while(scanf("%d", &n) != EOF){
sum_len = ;
init();
for(int i = ; i < n; i++){
int l;
scanf("%d %s", &l, s + sum_len);
for(int j = ; j < l; j++){
s_rev[sum_len + j] = s[sum_len + l - - j];
}
st[i] = sum_len;
sum_len += l;
ed[i] = sum_len - ; EXKMP(s, s_rev, st[i], ed[i], );
EXKMP(s_rev, s, st[i], ed[i], );
insertt(s, st[i], ed[i]);
} LL ans = ;
/*for(int i = 0; i < sum_len; i++){
cout<<s[i]<<" "<<flag[0][i]<<" "<<flag[1][i]<<endl;
}*/
//cout<<s<<endl;
for(int i = ; i < n; i++){
ans += searchh(s_rev, st[i], ed[i]);
}
printf("%lld\n", ans);
}
return ;
}

poj3376 Finding Palindromes【exKMP】【Trie】的更多相关文章

  1. POJ3376 Finding Palindromes —— 扩展KMP + Trie树

    题目链接:https://vjudge.net/problem/POJ-3376 Finding Palindromes Time Limit: 10000MS   Memory Limit: 262 ...

  2. 【BZOJ2741】【FOTILE模拟赛】L 分块+可持久化Trie树

    [BZOJ2741][FOTILE模拟赛]L Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max( ...

  3. 【hiho一下 第四周】Trie图

    [题目链接]:http://hihocoder.com/problemset/problem/1036?sid=1092555 [题意] [题解] AC自动机的模板题; 在求有没有子串的时候; 注意要 ...

  4. 【hiho一下第二周 】Trie树

    [题目链接]:http://hihocoder.com/problemset/problem/1014 [题意] [题解] 在字典树的域里面加一个信息cnt; 表示这个节点下面,记录有多少个单词; 在 ...

  5. 【spring源码分析】IOC容器初始化(二)

    前言:在[spring源码分析]IOC容器初始化(一)文末中已经提出loadBeanDefinitions(DefaultListableBeanFactory)的重要性,本文将以此为切入点继续分析. ...

  6. 「洛谷5283」「LOJ3048」「十二省联考2019」异或粽子【可持久化01trie+优先队列】

    题目链接 [洛谷传送门] [LOJ传送门] 题目大意 让你求区间异或和前\(k\)大的异或和的和. 正解 这道题目是Blue sky大佬教我做的(祝贺bluesky大佬进HA省A队) 我们做过某一些题 ...

  7. 【codeforces】【比赛题解】#855 Codefest 17

    神秘比赛,以<哈利波特>为主题……有点难. C题我熬夜切终于是写出来了,可惜比赛结束了,气啊. 比赛链接:点我. [A]汤姆·里德尔的日记 题意: 哈利波特正在摧毁神秘人的分灵体(魂器). ...

  8. 【BZOJ】【2434】【NOI2011】阿狸的打字机

    AC自动机+DFS序+BIT 好题啊……orz PoPoQQQ 大爷 一道相似的题目:[BZOJ][3172][TJOI2013]单词 那道题也是在fail树上数有多少个点,只不过这题是在x的fail ...

  9. 【洛谷5439】【XR-2】永恒(树链剖分,线段树)

    [洛谷5439][XR-2]永恒(树链剖分,线段树) 题面 洛谷 题解 首先两个点的\(LCP\)就是\(Trie\)树上的\(LCA\)的深度. 考虑一对点的贡献,如果这两个点不具有祖先关系,那么这 ...

随机推荐

  1. Quality of Service 0, 1 & 2

    来自:http://www.hivemq.com/blog/mqtt-essentials-part-6-mqtt-quality-of-service-levels Quality of Servi ...

  2. 〖Android〗我的ADT Eclipse定制

    1. 配置自动补全: Windows -> preferences -> 搜索assist,修改 java xml自动触发补全:.abcdefghijklmnopqrstuvwxyzABC ...

  3. 学习一个Vue模板项目

    最开始学习Vue的时候,不建议直接使用模板,而应该自己从头写起.模板都是人写的,要坚信"人能我能".只有自己亲自实践,才能促进自己主动思考,才能对模板.框架有深刻的理解. 在Git ...

  4. 性能测试工具jmeter的安装

    1.mac安装jmeter 参考博客:https://blog.csdn.net/shendezhuti/article/details/77972297

  5. 《网络编程》IPv4 与 IPv6 相互操作

    前言 因为互联网终端不断添加.IPv4 地址长度(32位)已不可以满足要求.所以出现了 IPv6地址(128位).可是现有应用程序大部分还是採用 IPv4 地址形式,所以必须解决 IPv4 与 IPv ...

  6. MUI中等待框的H5实现

    MUI没有内置的那个弹出转圈圈的那个等待框,那个nativeui.showwaiting是只能用于app中的,不能用在H5网页中的,网上找了下,找到个别人已经写好的,自己 测试了下没问题,先记下来 @ ...

  7. mysql服务启动、停止、重启

    如何启动/停止/重启MySQL 一.启动方式 1.使用 service 启动:service mysqld start 2.使用 mysqld 脚本启动:/etc/inint.d/mysqld sta ...

  8. ECMAScript 6 入门之字符串

    1.新增字符串的方法 1.字符是否存在 console.log("Yo".indexOf("Y")!=-1); console.log("Yo&quo ...

  9. pivot 与 unpivot函数

    pivot 与 unpivot函数 pivot 与 unpivot 函数是SQL05新提供的2个函数 灰常灰常的实用 ----------------------------------------- ...

  10. CEO退休

    早上刚来公司就收到群发邮件,说CEO退休了,在公司服务了22年.以后还是会part time做vice chairman.其实在公司也没打过几次照面...就知道是个和善的老人,祝他退休生活幸福! 我的 ...