题目链接: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)的更多相关文章

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

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

  2. POJ - 3376 Finding Palindromes(拓展kmp+trie)

    传送门:POJ - 3376 题意:给你n个字符串,两两结合,问有多少个是回文的: 题解:这个题真的恶心,我直接经历了5种错误类型 : ) ... 因为卡内存,所以又把字典树改成了指针版本的. 字符串 ...

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

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

  4. poj 3376 Finding Palindromes

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

  5. POJ 3376 Finding Palindromes(manacher求前后缀回文串+trie)

    题目链接:http://poj.org/problem?id=3376 题目大意:给你n个字符串,这n个字符串可以两两组合形成n*n个字符串,求这些字符串中有几个是回文串. 解题思路:思路参考了这里: ...

  6. POJ 3376 Finding Palindromes EX-KMP+字典树

    题意: 给你n个串串,每个串串可以选择和n个字符串拼接(可以自己和自己拼接),问有多少个拼接后的字符串是回文. 所有的串串长度不超过2e6: 题解: 这题由于是在POJ上,所以string也用不了,会 ...

  7. POJ - 3376 Finding Palindromes manacher+字典树

    题意 给n个字符串,两两拼接,问拼接后的\(n\times n\)个字符串中有多少个回文串. 分析 将所有正串插入字典树中,马拉车跑出所有串哪些前缀和后缀为回文串,记录位置,用反串去字典树中查询,两字 ...

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

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

  9. (简单) POJ 1961 Period,扩展KMP。

    Description For each prefix of a given string S with N characters (each character has an ASCII code ...

随机推荐

  1. js获取宽度设置thickbox百分比

    thickbox的宽高不好设为百分比,这样遇到不同的尺寸的电脑就会出现问题. 怎么做呢? 通过js来处理. <script type="text/javascript"> ...

  2. Pat(Advanced Level)Practice--1043(Is It a Binary Search Tree)

    Pat1043代码 题目描写叙述: A Binary Search Tree (BST) is recursively defined as a binary tree which has the f ...

  3. BOW

    bag of words(NLP): 最初的Bag of words,也叫做"词袋",在信息检索中,Bag of words model假定对于一个文本,忽略其词序和语法,句法,将 ...

  4. SQL学习之学会使用子查询

    1.SELECT语句是SQL的查询.我之前的随笔中所用的SELECT语句都是简单的查询,即从单个数据库表中检索数据的单条SELECT语句. 查询:任何SQL语句都是查询,但此术语一般指SELECT语句 ...

  5. ORACLE case when then

    Oracle CASE WHEN 用法介绍 1. CASE WHEN 表达式有两种形式 --简单Case函数 CASE sex WHEN '1' THEN '男' WHEN '2' THEN '女' ...

  6. iOS 导航条的影响

    如果是push出来的控制器,self.view的(0,0)点从状态栏下面开始: 如果有present出来的控制器,self.view的(0,0)点包含状态栏:

  7. URL编码解码

    ios url 编码和解码 1.url编码 ios中http请求遇到汉字的时候或者像是%…@#¥%&*这些字符的时候也可以使用下面的方法,需要转化成UTF-8,用到的方法是: NSString ...

  8. python打包成exe

    目前有三种方法可以实现python打包成exe,分别为 py2exe Pyinstaller cx_Freeze 其中没有一个是完美的 1.py2exe的话不支持egg类型的python库 2.Pyi ...

  9. ListView 条目加载上滑下滑首尾缩放动画实现

    要实现这个效果,只需要再适配器getView之前,给每个条目的view设置相应的动画即可. 首先需要2个动画的xml文件. 在res下新建anim文件夹:(res/anim) 第一个动画xml文件: ...

  10. 服务器搭建纪录linux+mysql+nginx+php

    新的项目启动 第一版 首先买了阿里云,选好环境镜像包,一键安装. 第一版php打算不用框架,完全手写,主要的功能点 数据交互和图片传输. 后台搭建好后,使用PHP的Laravel, web端还是选定b ...