题目链接: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. git ssh认证

    一般新手用git时,使用HTTPS都需要输入用户名和密码,这是一个很低效的开发过程.(虽然有时可以让开发人员减少push的次数).github提供了几种连接方式,其中以https:开头的代表https ...

  2. 如何制作一个类似Tiny Wings的游戏(2) Cocos2d-x 2.1.4

    在第二篇<如何制作一个类似Tiny Wings的游戏>基础上,增加添加主角,并且使用Box2D来模拟主角移动,原文<How To Create A Game Like Tiny Wi ...

  3. VisualStudio中的代码段

    VS很强大,在这里就不过多说了,在平时码代码时应用代码段会提高我们的编写速度. 举个例子: 比如输入Console.WriteLine (); 传统方法就是一个字母一个字母的输入进去. 如果大家掌握了 ...

  4. Bower前端包管理器

    bower 前端包管理器 为什么要用它 一个新的web项目开始,我们总是很自然地去下载需要用到的js类库文件,比如jQuery.随着项目的进展,我们可能又需要Bootstrap3,其中每个框架之间的依 ...

  5. BFC / hasLayout

    BFC - block formatting context 1.float的值不能为none 2.overflow的值不能为visible 3.display的值为table-cell,table- ...

  6. SSLSocket实现服务端和客户端双向认证的例子

    首先创建服务器端私有密钥和公共密钥1, keytool -genkey -alias serverkey -keystore kserver.ks    密码: serverpass2, keytoo ...

  7. pl sql项目演练--B2C商城项目

    项目学习视频下载地址:点击下载   1.注册会员及找回密码模块 }该模块主要功能有注册会员和找回密码 }注册会员:所需信息主要有:登录号.密码.真实姓名.性别.密码问题.密码答案.Email.地址.电 ...

  8. Sunny谈软件架构

    软件架构是软件工程一个很重要的分支,随着软件规模的扩大和软件寿命的延长,软件架构也越发重要.就像建筑领域,盖一个狗窝不需要进行分析与设计,但是如果是要盖一座万人体育场或者摩天大楼,那一定会离不开设计师 ...

  9. IIS上不能播放mp4

    iis不支持mp4格式,需要手动添加. 进入iis服务管理器,打开你的网站,然后点击MIME类型---添加(扩展名:mp4   MIME类型:application/octet-stream) 如此即 ...

  10. Android 汉字转拼音之JNI篇

    package com.tool.hz2py; import android.os.Bundle; import android.app.Activity; import android.view.M ...