题意:

给你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. 一起看下Apache1.3.22版本改进和修正了啥?

    Apache 1.3.20 - 1.3.22主要改进: 安全弱点: 1.在Apache1.3.20的win32平台上发现了一个漏洞.如果客户端发送一个非常长的URI可能导致用目录列表来代替缺省主页.4 ...

  2. delphi DBGrid简单自绘(字体颜色、背景等)

    delphi DBGrid简单自绘(字体颜色.背景等)  从网上找的代码 应该是C#写的,其实delphi 的操作类似: 1 2 3 4 5 6 7 8 9 10 11 12 13 void __fa ...

  3. Android中的Serialable和Parcelable的区别

    本文主要介绍Parcelable和Serializable的作用.效率.区别及选择,关于Serializable的介绍见<Java中的序列化Serialable高级详解> 1.作用 Ser ...

  4. ionic-CSS:ionic 表单和输入框

    ylbtech-ionic-CSS:ionic 表单和输入框 1.返回顶部 1. ionic 表单和输入框 list 类同样可以用于 input 元素.item-input 和 item 类指定了文本 ...

  5. JVM内核-原理、诊断与优化学习笔记(七):性能监控工具

    文章目录 系统性能监控 系统性能监控- linux uptime top vmstat(虚拟内存统计) pidstat 系统性能监控 - windows 任务管理器 Perfmon Process E ...

  6. Cookie自动管理

    如果想要对 cookies 干点什么就需要 HTTP Cookie 管理器了. 啥是 cookies 呢.储存在用户本地终端上的数据通常情况下,当用户结束浏览器会话 时,系统将终止所有的 Cookie ...

  7. STM32---初学者用库函数好还是直接对寄存器操作比较好

    引用:http://blog.csdn.net/u010349006/article/details/416 首先,两个都是C语言.从51过渡过来的话,就先说寄存器操作.每个MCU都有自己的寄存器,5 ...

  8. 一些CSS3新技术

    前些日子在SmashingMagazine看到一篇关于CSS3新技术不错的文章,它详细介绍了CSS3的新特性和它的使用方法,它包括:浏览器专有属性.选择器(属性选择器.连字符.伪类.伪元素).RGBA ...

  9. 常用指令linux总结

    linux的基础操作命令: 常见命令: man 查看帮助文档 用法:man + 命令 help 查看指定命令的用法 用法: 命令 --help(有空格) tab linux下命令与文件名补全 用法:在 ...

  10. C 常见字符串操作函数

    头文件 <string.h> 1. char *strstr(const char *str1, const char *str2);      判断str2是否为str1的子串  //s ...