题目链接:https://vjudge.net/problem/POJ-3376

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

题解:

可知:如果两字符串拼接起来能够形成回文串,那么短串的逆串是长串的前缀。

根据上述结论,我们可以:

1.利用扩展KMP算法求出每个字符串的后缀是否为回文串,以及每个字符串的逆串的后缀是否为回文串。

2.将每个字符串插入到Trie树中,并且Trie树的结点需要维护两个信息:当前结点的字符串数,以及往下有多少个回文串后缀。

3.用每个字符串的逆串去Trie树中查找。有两种情况:当前串作为长串,以及当前串作为短串。详情请看代码。

代码如下:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <sstream>
#include <algorithm>
using namespace std;
typedef long long LL;
const double eps = 1e-;
const int INF = 2e9;
const LL LNF = 9e18;
const int MAXN = 2e6+; char str[MAXN], res[MAXN];
int beg[MAXN], len[MAXN], ispal[][MAXN];
int Next[MAXN], exd[MAXN]; struct Node
{
int strnum;
int palnum;
int nxt[];
};
Node node[MAXN];
int tot, root; int newnode()
{
node[tot].strnum = ;
node[tot].palnum = ;
memset(node[tot].nxt, -, sizeof(node[tot].nxt));
tot++;
return tot-;
} void pre_EXKMP(char x[], int m)
{
Next[] = m;
int j = ;
while(+j<m && x[+j]==x[+j]) j++;
Next[] = j;
int k = ;
for(int i = ; i<m; i++)
{
int p = Next[k]+k-;
int L = Next[i-k];
if(i+L<=p) Next[i] = L;
else
{
j = max(, p-i+);
while(i+j<m && x[i+j]==x[+j]) j++;
Next[i] = j;
k = i;
}
}
} void EXKMP(char x[], int m, char y[], int n, int _L, int type)
{
pre_EXKMP(x, m);
int j = ;
while(j<n && j<m && x[j]==y[j]) j++;
exd[] = j;
int k = ;
for(int i = ; i<n; i++)
{
int p = exd[k]+k-;
int L = Next[i-k];
if(i+L<=p) exd[i] = L;
else
{
j = max(,p-i+);
while(i+j<n && j<m && y[i+j]==x[+j]) j++;
exd[i] = j;
k = i;
}
} //当type为0时,求的是字符串的后缀是否为回文串
//当type为1时,求的是字符串的逆串是否为回文串。实际就是求字符串的前缀是否为回文串。
for(int i = ; i<n; i++) //判断后缀是否为回文串
ispal[type][_L+i] = (i+exd[i]==n);
} void insert(char x[], int n, int L)
{
int tmp = root;
for(int i = ; i<n; i++)
{
int ch = x[i]-'a';
node[tmp].palnum += ispal[][L+i]; //如果后缀是回文串,就把统计数放在父节点。
if(node[tmp].nxt[ch]==-) node[tmp].nxt[ch] = newnode();
tmp = node[tmp].nxt[ch];
}
node[tmp].strnum++; //字符串数+1
} int search(char x[], int n, int L)
{
int ret = ;
int tmp = root;
for(int i = ; i<n; i++)
{
int ch = x[i]-'a';
tmp = node[tmp].nxt[ch];
if(tmp==-) break;
if((i<n-&&ispal[][L+i+]) || i==n-) //x作为长串,如果剩下的部分(后缀)是回文串
ret += node[tmp].strnum;
}
if(tmp!=-) ret += node[tmp].palnum; //x作为短串,加上后缀是回文串的长串
return ret;
} int main()
{
int n;
while(scanf("%d", &n)!=EOF)
{
tot = ;
root = newnode(); int L = ;
memset(ispal, , sizeof(ispal));
for(int i = ; i<n; i++)
{
//因为不确定每个字符串的最长长度,所以只好用地址的形式存储字符串
//用string的话,速度会变慢
scanf("%d%s", &len[i], str+L);
beg[i] = L;
L += len[i];
memcpy(res+beg[i], str+beg[i], len[i]);
reverse(res+beg[i], res+beg[i]+len[i]); EXKMP(res+beg[i], len[i], str+beg[i], len[i], beg[i], ); //求字符串后缀是否为回文串
EXKMP(str+beg[i], len[i], res+beg[i], len[i], beg[i], ); //求字符串的逆串的后缀(即字符串的前缀)是否为回文串。
insert(str+beg[i], len[i], beg[i]); //插入Trie树中
} LL ans = ;
for(int i = ; i<n; i++)
ans += search(res+beg[i], len[i], beg[i]); //用字符串的逆串去查找 printf("%lld\n", ans);
}
}

POJ3376 Finding Palindromes —— 扩展KMP + Trie树的更多相关文章

  1. POJ 3376 Finding Palindromes(扩展kmp+trie)

    题目链接:http://poj.org/problem?id=3376 题意:给你n个字符串m1.m2.m3...mn 求S = mimj(1=<i,j<=n)是回文串的数量 思路:我们考 ...

  2. poj3376 Finding Palindromes【exKMP】【Trie】

    Finding Palindromes Time Limit: 10000MS   Memory Limit: 262144K Total Submissions:4710   Accepted: 8 ...

  3. 【string】KMP, 扩展KMP,trie,SA,ACAM,SAM,最小表示法

    [KMP] 学习KMP,我们先要知道KMP是干什么的. KMP?KMPLAYER?看**? 正如AC自动机,KMP为什么要叫KMP是因为它是由三个人共同研究得到的- .- 啊跑题了. KMP就是给出一 ...

  4. KMP 、扩展KMP、Manacher算法 总结

    一. KMP 1 找字符串x是否存在于y串中,或者存在了几次 HDU1711 Number Sequence HDU1686 Oulipo HDU2087 剪花布条 2.求多个字符串的最长公共子串 P ...

  5. POJ 3376 Finding Palindromes (tire树+扩展kmp)

    很不错的一个题(注意string会超时) 题意:给你n串字符串,问你两两匹配形成n*n串字符串中有多少个回文串 题解:我们首先需要想到多串字符串存储需要trie树(关键),然后我们正序插入倒序匹配就可 ...

  6. 字符串 --- KMP Eentend-Kmp 自动机 trie图 trie树 后缀树 后缀数组

    涉及到字符串的问题,无外乎这样一些算法和数据结构:自动机 KMP算法 Extend-KMP 后缀树 后缀数组 trie树 trie图及其应用.当然这些都是比较高级的数据结构和算法,而这里面最常用和最熟 ...

  7. 【9.15校内测试】【寻找扩展可行域+特判】【Trie树 异或最小生成树】【模拟:)】

    之前都没做出来的同名题简直留下心理阴影啊...其实这道题还是挺好想的QAQ 可以发现,鸟可以走到的点是如下图这样扩展的: 由$(0,0)$向两边扩展,黑色是可以扩展到的点,红色是不能扩展的点,可以推出 ...

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

    Finding Palindromes Time Limit: 10000MS   Memory Limit: 262144K Total Submissions: 4043   Accepted: ...

  9. poj 3376 Finding Palindromes

    Finding Palindromes http://poj.org/problem?id=3376 Time Limit: 10000MS   Memory Limit: 262144K       ...

随机推荐

  1. rest-assured 将log()中的信息打印到log日志中去的方法

    rest-assured 将log()中的信息打印到log日志中去的方法: ============方法1============== PrintStream fileOutPutStream = n ...

  2. Query on The Trees(hdu 4010)

    题意: 给出一颗树,有4种操作: 1.如果x和y不在同一棵树上则在xy连边 2.如果x和y在同一棵树上并且x!=y则把x换为树根并把y和y的父亲分离 3.如果x和y在同一棵树上则x到y的路径上所有的点 ...

  3. Linux中有硬件时钟与系统时钟

    在Linux中有硬件时钟与系统时钟等两种时钟.硬件时钟是指主机板上的时钟设备,也就是通常可在BIOS画面设定的时钟.系统时钟则是指kernel中的时钟.当Linux启动时,系统时钟会去读取硬件时钟的设 ...

  4. My97DatePicker 时间控件

    <td> <input type="text" id="sendDate" name="sendDate" class=& ...

  5. meta标签集

    html中的meta总结: 0.声明文档使用的字符编码: <meta charset='utf-8'/> 1.优先使用 IE 最新版本和 Chrome : <meta http-eq ...

  6. git(一):了解、学习、安装git

    自述 一直到今天才真正的去了解学习使用git,看<git权威指南>这本书的第一篇,忽然有很多共鸣,比如在大学开始编程的时候,总是把写的所有demo和项目保存在U盘里,内存不够用就改为移动硬 ...

  7. Python3 MySQL 数据库连接 - PyMySQL 驱动 笔记

    sql插入语句(推荐): str_mac = "nihao" # SQL 插入语句 sql = "INSERT INTO EMPLOYEE(FIRST_NAME, \ L ...

  8. (入门SpringBoot)SpringBoot项目数据源以及整合mybatis(二)

    1.配置tomcat数据源: #   数据源基本配置spring.datasource.url=jdbc:mysql://localhost:3306/shoptest?useUnicode=true ...

  9. ios实现下载图片的裁减和显示

    使用如下的方法可以裁减的同时保证了不丢失像素. - (void)connectionDidFinishLoading:(NSURLConnection *)connection{    // Set ...

  10. 校园网、教育网 如何纯粹访问 IPv6 网站避免收费

    我国校园网有可靠的 IPv6 网络环境,速度非常快.稳定,并且大多数高校在网络流量计费时不会限制 IPv6 的流量,也就是免费的.然而访问 IPv4 商业网络时,则会收费,并且连接的可靠性一般.可幸的 ...