POJ 3376 Finding Palindromes (tire树+扩展kmp)
很不错的一个题(注意string会超时)
题意:给你n串字符串,问你两两匹配形成n*n串字符串中有多少个回文串
题解:我们首先需要想到多串字符串存储需要trie树(关键),然后我们正序插入倒序匹配就可以O(len)找到回文串个数了。
但是如果每次直接查询到结尾的话会漏掉两种情况
如: 1:a 与 ba 匹配(使用的是ab去匹配a)
2:ab 与 a 匹配
对于2这种情况我们需要在trie树记录每个字符串每个后缀可以形成回文串的个数(建树时就维护),对于1我们则需在匹配时看查询串每个后缀是否形成回文串。
扩展KMP:对于字符串str1的每一位与str2的最长前缀匹配记为ntand。
首先求得str1对于自己的每一位的“ntand”记为nnext,接着根据nnext求得ntand(两个函数想法与写法几乎一致)。
求nnext:我们首先暴力匹配第1个,接着根据字符串那面求得的匹配信息无回溯的求下一位
至于寻找每个后缀是否形成回文串我们使用扩展KMP的字符串正序和倒序的匹配长度来计算。
具体看代码
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<string>
#include<cstdio>
#include<cstring>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define eps 1E-8
/*注意可能会有输出-0.000*/
#define Sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型
#define Cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化
#define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0
#define mul(a,b) (a<<b)
#define dir(a,b) (a>>b)
typedef long long ll;
typedef unsigned long long ull;
const int Inf=<<;
const double Pi=acos(-1.0);
const int Mod=1e9+;
const int Max=;
struct node
{
int next[];
int coun,npd;//此处结束的单词个数 接下来是回文的单词个数
void init()
{
memset(next,,sizeof(next));
coun=npd=;
}
} trie[Max];
int nnext[Max],ntand[Max];
void Exnext(int len,char *str)//扩展KMP求next数组:是数组此对应位置与开头的最长公共前缀
{
nnext[]=len;
nnext[]=;
for(int i=; i+<len&&str[i]==str[i+]; ++i) //暴力匹配第二位
nnext[]++;
int k=;//最远匹配的下标
int p,l,j;
for(int i=; i<len; ++i)
{
p=k+nnext[k]-;
l=nnext[i-k];
if(i+l<=p)//可以画图来看,一定是匹配的
nnext[i]=l;
else
{
j=p-i+;//不确定的位置
if(j<)
j=;
while(i+j<len&&str[j]==str[i+j])//可以无回溯的暴力匹配
++j;
nnext[i]=j;
k=i;
}
}
return;
}
void Extand(int len,char *str1,char *str2)//两字符串的最长公共前缀
{
Exnext(len,str1);//正序的每一位和倒序相匹配 求辅助数组
ntand[]=;//之后与辅助数组一样
for(int i=; i<len&&str1[i]==str2[i]; ++i)
ntand[]++;
int k=;
int l,p,j;
for(int i=; i<len; ++i)
{
p=k+ntand[k]-;
l=nnext[i-k];
if(i+l<=p)
ntand[i]=l;
else
{
j=p-i+;
if(j<)
j=;
while(i+j<len&&str1[j]==str2[i+j])
++j;
ntand[i]=j;
k=i;
}
}
return ;
}
char str1[Max],str2[Max];
int len[Max],tot;
void Insert(int j,char *str)//trie树插入
{
int now=,mpos;
for(int i=; i<len[j]; ++i)
{
mpos=str[i]-'a';
if(!trie[now].next[mpos])
{
trie[now].next[mpos]=++tot;
trie[tot].init();
}
now=trie[now].next[mpos];
if(i<len[j]-&&ntand[i+]==len[j]-i-)//此位置之后是回文串
{
trie[now].npd++;
} }
trie[now].coun++;
return;
}
char str[Max];
ll Search(int j)
{
ll ans=0ll;
int now=,mpos;
for(int i=; i<len[j]; ++i)
{
mpos=str2[i]-'a';//倒序
if(!trie[now].next[mpos])
return ans;
now=trie[now].next[mpos];
if(i<len[j]-&&ntand[i+]==len[j]-i-)//此位置之后是回文串
ans+=(ll)trie[now].coun;
}
return ans+(ll)trie[now].coun+(ll)trie[now].npd;//匹配结束
}
int main()
{
int n;
while(~scanf("%d",&n))
{
tot=;
trie[tot].init();
int sum=;
for(int i=; i<n; ++i)
{
scanf("%d %s",&len[i],str+sum);
int coun=;
for(int j=len[i]-;j>=;--j) //倒序
str2[coun++]=str[j+sum];
for(int j=; j<len[i]; ++j)
str1[j]=str[j+sum];
str1[len[i]]=str2[len[i]]='\0';
Extand(len[i],str2,str1);
Insert(i,str1);//正序来插入
sum+=len[i];
}
ll ans=0ll;
sum=;
for(int i=; i<n; ++i)
{
for(int j=; j<len[i]; ++j)
{
str1[j]=str[j+sum];
str2[j]=str[len[i]-j-+sum];
}
str1[len[i]]=str2[len[i]]='\0';
Extand(len[i],str1,str2);
ans+=Search(i);//倒序查询
sum+=len[i];
}
printf("%lld\n",ans);
}
return ;
}
POJ 3376 Finding Palindromes (tire树+扩展kmp)的更多相关文章
- POJ - 3376 Finding Palindromes(拓展kmp+trie)
传送门:POJ - 3376 题意:给你n个字符串,两两结合,问有多少个是回文的: 题解:这个题真的恶心,我直接经历了5种错误类型 : ) ... 因为卡内存,所以又把字典树改成了指针版本的. 字符串 ...
- poj 3376 Finding Palindromes
Finding Palindromes http://poj.org/problem?id=3376 Time Limit: 10000MS Memory Limit: 262144K ...
- POJ 3376 Finding Palindromes(扩展kmp+trie)
题目链接:http://poj.org/problem?id=3376 题意:给你n个字符串m1.m2.m3...mn 求S = mimj(1=<i,j<=n)是回文串的数量 思路:我们考 ...
- POJ 3376 Finding Palindromes EX-KMP+字典树
题意: 给你n个串串,每个串串可以选择和n个字符串拼接(可以自己和自己拼接),问有多少个拼接后的字符串是回文. 所有的串串长度不超过2e6: 题解: 这题由于是在POJ上,所以string也用不了,会 ...
- POJ - 3376 Finding Palindromes manacher+字典树
题意 给n个字符串,两两拼接,问拼接后的\(n\times n\)个字符串中有多少个回文串. 分析 将所有正串插入字典树中,马拉车跑出所有串哪些前缀和后缀为回文串,记录位置,用反串去字典树中查询,两字 ...
- POJ 3376 Finding Palindromes(manacher求前后缀回文串+trie)
题目链接:http://poj.org/problem?id=3376 题目大意:给你n个字符串,这n个字符串可以两两组合形成n*n个字符串,求这些字符串中有几个是回文串. 解题思路:思路参考了这里: ...
- Kuangbin 带你飞 KMP扩展KMP Manacher
首先是几份模版 KMP void kmp_pre(char x[],int m,int fail[]) { int i,j; j = fail[] = -; i = ; while (i < m ...
- POJ3376 Finding Palindromes —— 扩展KMP + Trie树
题目链接:https://vjudge.net/problem/POJ-3376 Finding Palindromes Time Limit: 10000MS Memory Limit: 262 ...
- KMP+Tire树(模板)
\(\color{Red}{KMP板子}\) #include <bits/stdc++.h> using namespace std; const int maxn=1e6+9; int ...
随机推荐
- Coursera课程《Machine Learning》学习笔记(week1)
这是Coursera上比较火的一门机器学习课程,主讲教师为Andrew Ng.在自己看神经网络的过程中也的确发现自己有基础不牢.一些基本概念没搞清楚的问题,因此想借这门课程来个查漏补缺.目前的计划是先 ...
- VS2012如何显示行号
Tools-Options-Text Editor-All Languages –General – Display
- passback_params 支付回调的 原样返回字段 自定义字段的存放字段
开放平台文档中心 https://docs.open.alipay.com/204/105465/ passback_params String 否 512 公用回传参数,如果请求时传递了该参数,则返 ...
- SQLServer中exists和except用法
一.exists 1.1 说明 EXISTS(包括 NOT EXISTS)子句的返回值是一个BOOL值.EXISTS内部有一个子查询语句(SELECT ... FROM...),我将其称为EXIST的 ...
- .net 取得类的属性、方法、成员及通过属性名取得属性值
//自定义的类 model m = new model(); //取得类的Type实例 //Type t = typeof(model); //取得m的Type实例 Type t = m.G ...
- js四则运算符
只有当加法运算时,其中一方是字符串类型,就会把另一个也转为字符串类型.其他运算只要其中一方是数字,那么另一方就转为数字.并且加法运算会触发三种类型转换:将值转换为原始值,转换为数字,转换为字符串. & ...
- 常用代码块:创建httpclient
HttpGet httpGet = new HttpGet(url); SSLContext sslcontext = SSLContexts.custom() .loadTrustMaterial( ...
- 前端基础 & Bootstrap框架
Bootstrap介绍 Bootstrap是Twitter开源的基于HTML.CSS.JavaScript的前端框架. 它是为实现快速开发Web应用程序而设计的一套前端工具包. 它支持响应式布局,并且 ...
- locust基本使用
# coding:utf-8 from locust import HttpLocust,TaskSet,task class BlogDemo(TaskSet): '''用户行为:打开我的博客首页d ...
- 【Java工程师之路】[1-2.2]Java10个面向对象设计原则
面向对象设计原则是OOPS(Object-Oriented Programming System,面向对象的程序设计系统)编程的核心,但大多数Java程序员追逐像Singleton.Decorator ...