POJ 3376 Finding Palindromes(扩展kmp+trie)
题目链接:http://poj.org/problem?id=3376
题意:给你n个字符串m1、m2、m3...mn 求S = mimj(1=<i,j<=n)是回文串的数量
思路:我们考虑第i个字符串和第j个字符串能构成组合回文串要满足的条件:
1、i的长度小于j,那么i一定是j的反串的前缀,且j的反串剩下的后缀是回文串
2、i的长度等于j,那么i等于j的反串
3、i的长度大于j,那么j的反串一定是i的前缀,且i串剩下的后缀是回文串
我们可以将这n个字符串插入trie,每个节点要维护两个值:value1. 到当前节点的字符串个数;value2. 当前节点后面的回文子串个数
我们用每个字符串的反串去trie上查找,要构成回文串有以下情况:
1、 此反串是其他串的前缀,那么组合回文串的数量就要加上value2
2、此反串的前缀是某些字符串,且反串剩下的后缀是回文串,那么组合回文串的数量要加上value1
3、2的特例:此反串的前缀是某些字符串,且反串剩下的后缀为空,同样要加上value1,这种情况可以和2一起处理
关键:
1、判断字符串的哪些后缀是回文串(用于更新value2),以及对应反串的哪些后缀是回文串(当面临第二种情况时,可直接判断后缀否为回文串)
2、如何更新value1和value2(借助1的结果)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = ;
const int KIND = ; struct TrieNode
{
int num; // 到当前节点的字符串个数
int cnt; // 当前节点后面回文子串个数
TrieNode* nxt[];
}; TrieNode node[MAXN]; // 避免动态申请空间的时间消耗
TrieNode* root; // trie树的根节点
int bg[MAXN]; // bg[i]第i+1个字符串开始的位置
int ed[MAXN]; // ed[i]第i+1个字符串结束的位置
bool flag[][MAXN]; // flag[0][i]为true表示原串后面为回文串 flag[1][i]表示反串
char S[MAXN]; // 存放原串
char T[MAXN]; // 存放反串
int nxt[MAXN]; // 存放next数组
int extend[MAXN]; // 用于判断是否为回文子串
LL ans; // 保存结果
int tot; // node数组的下标 void GetNext(char* T, int lhs, int rhs)
{
int j = ;
while (lhs + j + <= rhs && T[lhs + j] == T[lhs + j + ]) ++j;
nxt[lhs + ] = j;
int k = lhs + ;
for (int i = lhs + ; i <= rhs; ++i)
{
int p = nxt[k] + k - ;
int L = nxt[lhs + i - k];
if (L + i < p + ) nxt[i] = L;
else
{
j = max(, p - i + );
while (i + j <= rhs && T[lhs + j] == T[i + j]) ++j;
nxt[i] = j;
k = i;
}
}
} void ExtendKMP(char* S, char* T, int lhs, int rhs, bool sign)
{
GetNext(T, lhs, rhs);
int j = ;
while (j + lhs <= rhs && S[j + lhs] == T[j + lhs]) ++j;
extend[lhs] = j;
int k = lhs;
for (int i = lhs + ; i <= rhs; ++i)
{
int p = extend[k] + k - ;
int L = nxt[lhs + i - k];
if (L + i < p + ) extend[i] = L;
else
{
j = max(, p - i + );
while (i + j <= rhs && S[i + j] == T[lhs + j]) ++j;
extend[i] = j;
k = i;
}
}
for (int i = lhs; i <= rhs; ++i)
{
if (extend[i] == rhs - i + )
flag[sign][i] = true;
}
} void Insert(char S[], int lhs, int rhs)
{
TrieNode* temp = root;
for (int i = lhs; i <= rhs; ++i)
{
int ch = S[i] - 'a';
temp->cnt += flag[][i]; // 更新当前节点后面回文子串的数目
if (temp->nxt[ch] == NULL) temp->nxt[ch] = &node[tot++];
temp = temp->nxt[ch];
}
++temp->num; // 更新到当前节点的字符串数目
} void Search(char S[], int lhs, int rhs)
{
TrieNode* temp = root;
for (int i = lhs; i <= rhs; ++i)
{
int ch = S[i] - 'a';
temp = temp->nxt[ch];
if (temp == NULL) break;
if ((i < rhs && flag[][i + ]) || i == rhs)
ans += temp->num;
}
if (temp) ans += temp->cnt;
} int main()
{
int n;
while (scanf("%d", &n) != EOF)
{
// 初始化
tot = ;
ans = ;
memset(node, , sizeof(node));
memset(flag, , sizeof(flag));
root = &node[tot++]; int l = ;
int L = ;
for (int i = ; i < n; ++i)
{
// 输入一组数据
scanf("%d", &l);
scanf("%s", S + L); // 生成反串
for (int j = ; j < l; ++j)
T[L + j] = S[L + l - - j]; bg[i] = L;
ed[i] = L + l - ; ExtendKMP(S, T , bg[i], ed[i], );
ExtendKMP(T, S , bg[i], ed[i], );
Insert(S, bg[i], ed[i]); L += l;
} for (int i = ; i < n; ++i)
Search(T, bg[i], ed[i]); printf("%lld\n", ans);
}
return ;
}
POJ 3376 Finding Palindromes(扩展kmp+trie)的更多相关文章
- POJ3376 Finding Palindromes —— 扩展KMP + Trie树
题目链接:https://vjudge.net/problem/POJ-3376 Finding Palindromes Time Limit: 10000MS Memory Limit: 262 ...
- POJ - 3376 Finding Palindromes(拓展kmp+trie)
传送门:POJ - 3376 题意:给你n个字符串,两两结合,问有多少个是回文的: 题解:这个题真的恶心,我直接经历了5种错误类型 : ) ... 因为卡内存,所以又把字典树改成了指针版本的. 字符串 ...
- POJ 3376 Finding Palindromes (tire树+扩展kmp)
很不错的一个题(注意string会超时) 题意:给你n串字符串,问你两两匹配形成n*n串字符串中有多少个回文串 题解:我们首先需要想到多串字符串存储需要trie树(关键),然后我们正序插入倒序匹配就可 ...
- poj 3376 Finding Palindromes
Finding Palindromes http://poj.org/problem?id=3376 Time Limit: 10000MS Memory Limit: 262144K ...
- POJ 3376 Finding Palindromes(manacher求前后缀回文串+trie)
题目链接:http://poj.org/problem?id=3376 题目大意:给你n个字符串,这n个字符串可以两两组合形成n*n个字符串,求这些字符串中有几个是回文串. 解题思路:思路参考了这里: ...
- POJ 3376 Finding Palindromes EX-KMP+字典树
题意: 给你n个串串,每个串串可以选择和n个字符串拼接(可以自己和自己拼接),问有多少个拼接后的字符串是回文. 所有的串串长度不超过2e6: 题解: 这题由于是在POJ上,所以string也用不了,会 ...
- POJ - 3376 Finding Palindromes manacher+字典树
题意 给n个字符串,两两拼接,问拼接后的\(n\times n\)个字符串中有多少个回文串. 分析 将所有正串插入字典树中,马拉车跑出所有串哪些前缀和后缀为回文串,记录位置,用反串去字典树中查询,两字 ...
- 【string】KMP, 扩展KMP,trie,SA,ACAM,SAM,最小表示法
[KMP] 学习KMP,我们先要知道KMP是干什么的. KMP?KMPLAYER?看**? 正如AC自动机,KMP为什么要叫KMP是因为它是由三个人共同研究得到的- .- 啊跑题了. KMP就是给出一 ...
- (简单) POJ 1961 Period,扩展KMP。
Description For each prefix of a given string S with N characters (each character has an ASCII code ...
随机推荐
- Unix/Linux环境C编程入门教程(15) BT5开发环境搭建
1. Backtrack 是处于世界领先地位的渗透测试和信息安全审计发行版本.有着上百种预先安装好的工具软件,并确定能完美运行,Backtrack5 提供了一个强大的渗透测试平台--从Web hack ...
- 【转】Ubuntu Linux 下文件名乱码(无效的编码)的快速解决办法
原博文地址:http://www.cnblogs.com/york-hust/archive/2012/07/07/2580388.html 文件是在WIndows 下创建的,Windows 的文件名 ...
- PHP 操作redis 详细讲解转的
http://www.cnblogs.com/jackluo/p/3412670.html phpredis是redis的php的一个扩展,效率是相当高有链表排序功能,对创建内存级的模块业务关系 很有 ...
- html学习笔记一
学习了一天,总结巩固下自己收获. html是超文本标记语言,而不是编程语言. 1:html结构 包含html标签,head标签,title标签,body标签. <html> <hea ...
- Rikka with Graph(联通图取边,暴力)
Rikka with Graph Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) ...
- 开源 免费 java CMS - FreeCMS1.9 简历管理
项目地址:http://code.google.com/p/freecms/ 简历管理 管理当前管理网站的简历数据. 1. 回复简历 选择须要回复的简历.然后点击"回复". 注意: ...
- iOS深入学习 (Block全面分析)
本文翻译自苹果的文档,有删减,也有添加自己的理解部分. 如果有Block语法不懂的,可以参考fuckingblocksyntax,里面对于Block 为了方便对比,下面的代码我假设是写在ViewCon ...
- MyDatePicker拆分日期显示到不同TextBox
如图所示效果:年—月—日 时—分—秒 <tr> <td align="center" style="background- ...
- 转场动画2-Pop动画
上一篇试讲push动画,这篇分解pop动画 里面关于矩阵有不懂得,参考CATransform3D 特效详解 上图(虚拟机下,图是渣渣 ) 代码直接上 // // PopTransition.h // ...
- 在C#调用C++的DLL方法(一)生成非托管dll
C#与C/C++相比,前者的优势在于UI,后者的优势在于算法,C++下的指针虽然恶心,若使用得当还是相当方便的,最重要的问题是,市面上很多流行的开发工具库,几乎没有不支持C++的,但全面支持C#只能说 ...