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. eclipse alt+/智能提示错误问题

    转自: https://blog.csdn.net/u013066244/article/details/69054447

  2. 简单的redis测试

    //这个方法会多一次 public function testRedisList(){ $num = 10; $user_id = uniqid(); //直接链接本地的redis $redis = ...

  3. 【C#】详解C#事件

    目录结构: contents structure [+] 事件基本介绍 定义事件类型 定义事件成员 定义引发事件的方法 以线程安全的方式引发事件 登记事件关注 揭秘事件 显式实现事件 为什么需要显式实 ...

  4. 【Windows】Dos中的日期的和时间

    在Dos中,我们可以通过动态变量DATE来取得当前日期,通过动态变量TIME来取得当前日期.实例1 C:\Users\hubin5>echo %date% 2013/03/11 周一 C:\Us ...

  5. SNF快速开发平台--多组织+多平台+多系统处理方案

    多组织架构的集团要看组织的组成形式: 1.如果每个组织都是独立法人,这个相对来说简单一些,组织之间的关联交易跟集团外部客户交易没什么本质区别, 各个公司都是独立核算,正常的应收应付都需要开发票,各自出 ...

  6. 记一次性能优化,限制tcp_timewait数量,快速回收和重用

    前言 这篇文章的主题是记录一次Python程序的性能优化,在优化的过程中遇到的问题,以及如何去解决的.为大家提供一个优化的思路,首先要声明的一点是,我的方式不是唯一的,大家在性能优化之路上遇到的问题都 ...

  7. Socket网络编程--聊天程序(1)

    很早的一段时间,看了APUE和UNPv1了解了网络编程,但是但是只是看而已,没有具体的实践,趁现在没有什么事做,就来实践了解一下网络编程.写博客保存下来,方便以后用到的时候可以查到. 此次的聊天程序是 ...

  8. Android截图命令screencap与视频录制命令screenrecord

    Android截图命令screencap 查看帮助命令 bixiaopeng@bixiaopeng ~$ adb shell screencap -v screencap: invalid optio ...

  9. 一篇文全面了解DevOps:从概念、关键问题、兴起到实现需求

    一篇文全面了解DevOps:从概念.关键问题.兴起到实现需求 转自:一篇文全面了解DevOps:从概念.关键问题.兴起到实现需求 2018-06-06 目前在国外,互联网巨头如Google.Faceb ...

  10. idea language level 介绍

    language level 介绍 其他 IDE 没有看到类似 language level 的设置,所以这个功能应该算是 IntelliJ IDEA 特有的,可是 IntelliJ IDEA 官网也 ...