题目链接:https://cn.vjudge.net/contest/283743#problem/B

题目大意:给你n个字符串,然后问你将这位n个字符串任意两两组合,然后问你这所有的n*n种情况中,是回文串的有多少个?

题目大意:学到了一个很骚气的存储多个零散字符串的方法,因为有可能个给你很多零散的字符串,我们可以将这些字符串存储在一个字符串里面,然后再额外加一个数组记录每一个字符串的开始位置和截止位置就好了。 然后是对于这个题,首先说一下判断字符串的方法,对于每一个字符串我们通过manacher算法求出每一个点的最长的回文串,然后在字典树中反序存储这个字符串。

举个例子:aaba和baa,这个时候baa插在aaba后面是可以构成回文串的,在字典树中baa是倒序存储的,所以就能够和aaba的前缀aab相匹配,然后我们在看aab后面的子串是不是回文串,如果是回文串的话,这个两个就能够形成回文串,因为前面部分和后面部分是对称的,并且中间部分也是回文串。

我们对于每一个字符串,

surf[i]记录的是对于当前的字符串,从第i+1个位置开始,能不能构成字符串。

pre[i]数组记录的是对于当前的字符串,从当前字符串的第一个位置开始到第i-1个位置,前缀能不能构成回文串。

val[i]数组记录的是字典树中从第0个位置到i所形成的的字符串的个数。

qian[i]数组记录的是当前节点后面是回文串的数目。

查询的时候,一共有两种情况:

一种是题目中说的aaba和bba这种情况,到了某一个字符串的位置之后,这个位置之前的有对称的字符串,这个位置之后的是一个回文串。

另一种是一个字符串是回文串,一直到底部都是能构成回文串的,这个时候还应该加上一直到这个字符串底部的回文串的个数就可以了。

每一次查询当前节点后面是不是回文串,如果是的话就加上这个字符串的个数。如果找到了底部还需要注意后面形成的回文串的个数。

AC代码:

 #include<iostream>
#include<stack>
#include<iomanip>
#include<cmath>
#include<stdio.h>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
# define ll long long
const int maxn = 2e6+;
const int maxm= 2e6+;
char str[maxn],tmp[maxn<<];
bool pre[maxn],suf[maxn];
int pp[maxn<<],tot;
int qian[maxn],val[maxn];
int start[maxn];
int ch[maxn][];
void init()
{
for(int i=; i<=tot; i++)
{
qian[i]=,val[i]=;
for(int j=; j<; j++)
{
ch[i][j]=;
}
}
tot=;
}
void trie(int t)
{
int p=;
for(int i=start[t+]-; i>=start[t]; i--)
{
int tmp=str[i]-'a';
qian[p]+=pre[i];
if(!ch[p][tmp])
ch[p][tmp]=++tot;
p=ch[p][tmp];
}
val[p]+=;
}
void manacher(int n)
{
int i,mx=,len=,id=;
tmp[]='$';
for(i=start[n]; i<start[n+]; i++)
{
tmp[len++]='#';
tmp[len++]=str[i];
pre[i]=;
suf[i]=;
}
tmp[len]='#';
tmp[len+]=;
for(int i=; i<len; i++)
{
pp[i] = ;
if(pp[id]+id > i)
pp[i] = min(pp[id*-i], pp[id]+id-i);
while(tmp[ i+pp[i] ] == tmp[ i-pp[i] ])
pp[i]++;
if(pp[id]+id < pp[i]+i)
id = i;
if(pp[i]==i)
pre[start[n]+pp[i]-]=;
if(i+pp[i]-==len)
suf[start[n+]-pp[i]+]=;
}
}
ll query(int t)
{
ll sum=;
int p=,i;
for( i=start[t]; i<start[t+]; i++)
{
int tmp=str[i]-'a';
if(ch[p][tmp]==)
break;
p=ch[p][tmp];
if(suf[i+]==||i+==start[t+])
sum+=val[p];
}
if(i==start[t+])
sum+=qian[p];
return sum;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
init();
int len;
for(int i=; i<=n; i++)
{
scanf("%d%s",&len,str+start[i]);
start[i+]=start[i]+len;
manacher(i);
trie(i);
}
ll ans=;
for(int i=; i<=n; i++)
{
ans+=query(i);
}
printf("%lld\n",ans);
}
return ;
}

最新文章

  1. .net使用正则表达式校验、匹配字符工具类
  2. 【原创】kafka controller源代码分析(二)
  3. Spring使用——切面编程AOP使用
  4. webservice可以访问但是不能调用方法
  5. Hook to function
  6. javascript权威指南笔记--javascript语言核心(二)
  7. grumble.js
  8. android118 上拉下拉刷新列表listView实现
  9. 相关Python分割操作
  10. FZU 2091 播放器(栈应用)
  11. 教你如何一键反编译获取任何微信小程序源代码(图形化界面,傻瓜式操作)
  12. (栈 注意格式)P1739 表达式括号匹配 洛谷
  13. 设计模式---行为变化模式之命令模式(Command)
  14. java Calendar 入门【转】
  15. Eclipse启动报错An internal error occurred during: &quot;Initializing Java Tooling&quot;
  16. 洛谷 P1135 奇怪的电梯 【基础BFS】
  17. Unity3D实践系列09, 物理引擎与碰撞检测
  18. 【伊利丹】Hadoop2.0 NN HA实验记录
  19. Xcode 各版本简介
  20. eclipse从svn导入maven项目变成普通项目解决办法

热门文章

  1. Django-website 程序案例系列-17 forms表单验证的字段解释
  2. 平衡树及笛卡尔树讲解(旋转treap,非旋转treap,splay,替罪羊树及可持久化)
  3. Redis报错总结
  4. hdu1728 逃离迷宫
  5. IDEA在debug时修改变量值
  6. MT【228】整数解的个数
  7. LOJ #2802. 「CCC 2018」平衡树(整除分块 + dp)
  8. 自学Linux Shell1.1-Linux初识
  9. 自学Linux Shell5.1-shell父子关系
  10. 【BZOJ3817/UOJ42】Sum(类欧)