题意:

给你n个串串,每个串串可以选择和n个字符串拼接(可以自己和自己拼接),问有多少个拼接后的字符串是回文。

所有的串串长度不超过2e6;

题解:

这题由于是在POJ上,所以string也用不了,会tle。

串串个数也比较多,开不下二维的char数组,卡内存。

所以数据的预处理需要处理成一个串串,把所有的串串放在一个串里面。

记录每一个串串的起始位置和长度。

数据预处理部分就解决了。

然后就是核心思想部分了。

首先你要知道如何用EX_KMP求串串前缀和后缀是否是回文。(其实也可以用马拉车)

其实这个就是t串等于s串的反串,然后做一个EX_KMP就可以了。

不会的可以做做这一题  Best Reward HDU - 3613

于是我们处理出了所有串串的前缀和后缀是否是一个回文。

下面看这个例子 dedabc 和 cba 这个显然就是可以拼接成回文的。

由此很容易想到用字典树写这一题。

然后有3种情况

1、s的长度 > t的长度,t的反串是s的前缀,s剩下的部分是回文串。

2、s的长度 < t的长度,s的反串是t的前缀,t剩下的部分是回文串。

3、s的长度 = t的长度,t的反串等于s。

然后就是具体做法,正串放入字典树内,如果某个位置的的下一个位置pos是一个回文(这个根据上面的EX_KMP处理出来)val[pos]++;

插入完后就在最后一个节点的位置pos,ed[pos]++;

最后一步计算答案;

字典树里面存的是正串,所以查询使用反串去进行匹配,

第1种情况,假设当前节点为u,对于当前节点i,当i<len-1且从第i+1个字母往后是一个回文串的时候,ans+=ed[u]。

第2种情况,如果我们顺利的查找到s反串的尾节点u,则ans+=val[u]。

第3种情况,假设当前节点为u,对于当前节点i,当i==len-1的时候,ans+=ed[u]。

最近正在学习串串,这是我遇到的第一道需要思考的题目,感觉还是可以的。

博客鸽了这么久,是时候开始写了。

 #include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <algorithm>
#include <set>
#include <iostream>
#include <map>
#include <stack>
#include <string>
#include <time.h>
#include <vector>
#define pi acos(-1.0)
#define eps 1e-9
#define fi first
#define se second
#define rtl rt<<1
#define rtr rt<<1|1
#define bug printf("******\n")
#define mem(a,b) memset(a,b,sizeof(a))
#define name2str(x) #x
#define fuck(x) cout<<#x" = "<<x<<endl
#define f(a) a*a
#define sf(n) scanf("%d", &n)
#define sff(a,b) scanf("%d %d", &a, &b)
#define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)
#define sffff(a,b,c,d) scanf("%d %d %d %d", &a, &b, &c, &d)
#define pf printf
#define FRE(i,a,b) for(i = a; i <= b; i++)
#define FREE(i,a,b) for(i = a; i >= b; i--)
#define FRL(i,a,b) for(i = a; i < b; i++)+
#define FRLL(i,a,b) for(i = a; i > b; i--)
#define FIN freopen("data.txt","r",stdin)
#define gcd(a,b) __gcd(a,b)
#define lowbit(x) x&-x
#define rep(i,a,b) for(int i=a;i<b;++i)
#define per(i,a,b) for(int i=a-1;i>=b;--i)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int maxn = 2e6 + ;
const int maxm = 8e6 + ;
const int INF = 0x3f3f3f3f;
const int mod = ;
int nxt[maxn], extend[maxn], len[maxn], vis[][maxn];
char s[maxn], t[maxn];
void pre_EKMP ( char x[], int m, int nxt[] ) {
nxt[] = m;
int j = ;
while ( j + < m && x[j] == x[j + ] ) j++;
nxt[] = j;
int k = ;
for ( int i = ; i < m; i++ ) {
int p = nxt[k] + k - ;
int L = nxt[i - k];
if ( i + L < p + ) nxt[i] = L;
else {
j = max ( , p - i + );
while ( i + j < m && x[i + j] == x[j] ) j++;
nxt[i] = j;
k = i;
}
}
}
void EKMP ( char x[], int m, char y[], int n, int nxt[], int extend[], int _L, int flag ) {
pre_EKMP ( x, m, nxt );
int j = ;
while ( j < n && j < m && x[j] == y[j] ) j++;
extend[] = j;
int k = ;
for ( int i = ; i < n; i++ ) {
int p = extend[k] + k - ;
int L = nxt[i - k];
if ( i + L < p + ) extend[i] = L;
else {
j = max ( , p - i + );
while ( i + j < n && j < m && y[i + j] == x[j] ) j++;
extend[i] = j;
k = i;
}
}
for ( int i = ; i < n ; i++ )
vis[flag][_L + i] = ( i + extend[i] == n );
} struct Trie {
int ch[maxn][], val[maxn], ed[maxn];
int sz;
void init() {
memset ( ch[], , sizeof ( ch[] ) );
sz = , val[] = , ed[] = ;
}
void add ( char *s, int n, int L ) {
int u = ;
for ( int i = ; i < n; i++ ) {
int id = s[i] - 'a';
val[u] += vis[][L + i];
if ( !ch[u][id] ) {
ch[u][id] = ++sz;
memset ( ch[sz], , sizeof ( ch[sz] ) );
val[sz] = ;
ed[sz] = ;
}
u = ch[u][id];
}
ed[u]++;
}
int find ( char *s, int n, int L ) {
int u = , ret = ;
for ( int i = ; i < n; i++ ) {
int id = s[i] - 'a';
u = ch[u][id];
if ( !u ) break;
if ( ( i < n - && vis[][L + i + ] ) || i == n - )
ret += ed[u];
}
if ( u ) ret += val[u];
return ret;
}
} trie;
int n;
int main() {
while ( ~sf ( n ) ) {
mem ( vis, );
trie.init();
int tot = ;
for ( int i = ; i < n ; i++ ) {
scanf ( "%d%s", &len[i], s + tot );
memcpy ( t + tot, s + tot, len[i] );
reverse ( t + tot, t + tot + len[i] );
EKMP ( t + tot, len[i], s + tot, len[i], nxt, extend, tot, );
EKMP ( s + tot, len[i], t + tot, len[i], nxt, extend, tot, );
trie.add ( s + tot, len[i], tot );
tot += len[i];
}
LL ans = ;
tot = ;
for ( int i = ; i < n ; i++ ) {
ans += trie.find ( t + tot, len[i], tot );
tot += len[i];
}
printf ( "%lld\n", ans );
}
return ;
}

POJ 3376 Finding Palindromes EX-KMP+字典树的更多相关文章

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

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

  2. poj 3376 Finding Palindromes

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

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

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

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

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

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

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

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

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

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

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

  8. POJ 3764 - The xor-longest Path - [DFS+字典树变形]

    题目链接:http://poj.org/problem?id=3764 Time Limit: 2000MS Memory Limit: 65536K Description In an edge-w ...

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

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

随机推荐

  1. windows常用

    host文件位置:C:\Windows\System32\drivers\etc

  2. 小程序生成海报:通过 json 配置方式轻松制作一张海报图

    背景 由于我们无法将小程序直接分享到朋友圈,但分享到朋友圈的需求又很多,业界目前的做法是利用小程序的 Canvas 功能生成一张带有二维码的图片,然后引导用户下载图片到本地后再分享到朋友圈.而小程序 ...

  3. 【Codeforces Round #429 (Div. 2) B】 Godsend

    [Link]:http://codeforces.com/contest/841/problem/B [Description] 两个人轮流对一个数组玩游戏,第一个人可以把连续的一段为奇数的拿走,第二 ...

  4. Dll注入技术之注册表注入

    DLL注入技术之REG注入 DLL注入技术指的是将一个DLL文件强行加载到EXE文件中,并成为EXE文件中的一部分,这样做的目的在于方便我们通过这个DLL读写EXE文件内存数据,(例如 HOOK EX ...

  5. Delphi 2010 中的泛型

    Delphi 2010 中的泛型 2010已发布很长时间了,口碑还不错,准备用它开发下一项目,但对泛型等新东西的认识还不够,就搜了一下,发现下面这篇文章,还不错,大家一起补补课吧! C++中的模板.C ...

  6. 剑指offer——26树的子结构

    题目描述 输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构)   题解: 注意,所谓的子结构,是树的形状和值相同,并非判断B是不是A的一部分[如果是这样,那就是 ...

  7. Poi设置列样式

    最近做的项目中用到Poi导出Excel文件做模板,其中有的列需要设置为文本格式,查资料发现都是给单元格设置样式,由于是模板单元格都没内容,所以不能通过设置单元格式样式的方式操作,网上有说法是不能设置列 ...

  8. SqlMapClient operation; bad SQL grammar []; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException: InlineParameterMap

    <select id="getResByName" resultClass="Resources" parameterClass="java.l ...

  9. 初学者学习PHP开发应该掌握的几段精华代码

    来自:http://hi.baidu.com/dckhello/item/d62b16d8994bf93449e1ddb0 经典循环例子 <HTML><HEAD><TIT ...

  10. java 打印1到n之间的整数

    package java_day08; /* * 打印1-n之间的整数 * * 递归:方法体自己调用自己 */ public class DiGui { public static void main ...