很不错的一个题(注意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)的更多相关文章

  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. POJ 3376 Finding Palindromes(扩展kmp+trie)

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

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

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

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

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

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

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

  7. Kuangbin 带你飞 KMP扩展KMP Manacher

    首先是几份模版 KMP void kmp_pre(char x[],int m,int fail[]) { int i,j; j = fail[] = -; i = ; while (i < m ...

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

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

  9. KMP+Tire树(模板)

    \(\color{Red}{KMP板子}\) #include <bits/stdc++.h> using namespace std; const int maxn=1e6+9; int ...

随机推荐

  1. Android无线测试之—UiAutomator UiDevice API介绍八

    获取包名.开启通知栏.快速设置.获取布局文件的方法 一.包名.通知栏.快速设置.布局文件等相关知识: 1)包名:标示应用的符号,每个应用的名字 2)通知栏:从主界面的顶端向下拉,就可以打开通知栏 3) ...

  2. LightOJ1089

    题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=26806 题目大意:略 题目思路:前缀和与离散化 可用线段树做,但是 ...

  3. 九度OJ 1359:大魏树遍历 (树)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:299 解决:29 题目描述: 大魏是JOBDU技术组里最喜欢折腾的一个了,单反.骑车.改九度页面,当然还有YY prado.我们姑且先把这些 ...

  4. Server Objects Extension(SOE)开发(一)

    1.SOE相关 1.1 什么是SOE SOE(Server对象扩展:Server Object Extenstion),其通过采用ArcObjects的相关的接口.类库对ArcGIS Server的基 ...

  5. Python3.6全栈开发实例[006]

    6.检查传入字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者. dic = {"k1": "v1v1", " ...

  6. Linux中的日志功能

    配置文件 /etc/logrotate.conf daily 日志的轮替周期是每天weekly 日志的轮替周期是每周monthly 日志的轮替周期是每月rotate 数字 保留的日志文件的个数comp ...

  7. scrapy+mongodb报错 TypeError: name must be an instance of str

    经过各种排查,最后找到原因,在settings文件中配置文件大小写写错了,在pipelines中 mongo_db=crawler.settings.get('MONGODB_DB'),get 获取的 ...

  8. HAProxy的访问控制

    HAProxy的ACL用于实现基于请求报文首部.响应报文的内容或其他的环境状态信息来做出转发决策,这大大增强了其配置弹性,其配置法则通常分为两步,首先去定义ACL,即定义一个测试条件,而后在条件得到满 ...

  9. key points & (QA) about RPKI

    @1: Q: What does ROA look like?Since ROA means which ASes are allowed for originating routes to some ...

  10. 联合文件系统 unionfs