题目链接: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代码:

  1. #include<iostream>
  2. #include<stack>
  3. #include<iomanip>
  4. #include<cmath>
  5. #include<stdio.h>
  6. #include<algorithm>
  7. #include<string>
  8. #include<cstring>
  9. using namespace std;
  10. # define ll long long
  11. const int maxn = 2e6+;
  12. const int maxm= 2e6+;
  13. char str[maxn],tmp[maxn<<];
  14. bool pre[maxn],suf[maxn];
  15. int pp[maxn<<],tot;
  16. int qian[maxn],val[maxn];
  17. int start[maxn];
  18. int ch[maxn][];
  19. void init()
  20. {
  21. for(int i=; i<=tot; i++)
  22. {
  23. qian[i]=,val[i]=;
  24. for(int j=; j<; j++)
  25. {
  26. ch[i][j]=;
  27. }
  28. }
  29. tot=;
  30. }
  31. void trie(int t)
  32. {
  33. int p=;
  34. for(int i=start[t+]-; i>=start[t]; i--)
  35. {
  36. int tmp=str[i]-'a';
  37. qian[p]+=pre[i];
  38. if(!ch[p][tmp])
  39. ch[p][tmp]=++tot;
  40. p=ch[p][tmp];
  41. }
  42. val[p]+=;
  43. }
  44. void manacher(int n)
  45. {
  46. int i,mx=,len=,id=;
  47. tmp[]='$';
  48. for(i=start[n]; i<start[n+]; i++)
  49. {
  50. tmp[len++]='#';
  51. tmp[len++]=str[i];
  52. pre[i]=;
  53. suf[i]=;
  54. }
  55. tmp[len]='#';
  56. tmp[len+]=;
  57. for(int i=; i<len; i++)
  58. {
  59. pp[i] = ;
  60. if(pp[id]+id > i)
  61. pp[i] = min(pp[id*-i], pp[id]+id-i);
  62. while(tmp[ i+pp[i] ] == tmp[ i-pp[i] ])
  63. pp[i]++;
  64. if(pp[id]+id < pp[i]+i)
  65. id = i;
  66. if(pp[i]==i)
  67. pre[start[n]+pp[i]-]=;
  68. if(i+pp[i]-==len)
  69. suf[start[n+]-pp[i]+]=;
  70. }
  71. }
  72. ll query(int t)
  73. {
  74. ll sum=;
  75. int p=,i;
  76. for( i=start[t]; i<start[t+]; i++)
  77. {
  78. int tmp=str[i]-'a';
  79. if(ch[p][tmp]==)
  80. break;
  81. p=ch[p][tmp];
  82. if(suf[i+]==||i+==start[t+])
  83. sum+=val[p];
  84. }
  85. if(i==start[t+])
  86. sum+=qian[p];
  87. return sum;
  88. }
  89. int main()
  90. {
  91. int n;
  92. while(~scanf("%d",&n))
  93. {
  94. init();
  95. int len;
  96. for(int i=; i<=n; i++)
  97. {
  98. scanf("%d%s",&len,str+start[i]);
  99. start[i+]=start[i]+len;
  100. manacher(i);
  101. trie(i);
  102. }
  103. ll ans=;
  104. for(int i=; i<=n; i++)
  105. {
  106. ans+=query(i);
  107. }
  108. printf("%lld\n",ans);
  109. }
  110. return ;
  111. }

B - Finding Palindromes (字典树+manacher)的更多相关文章

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

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

  2. Finding Palindromes - 猥琐的字符串(Manacher+trie)

    题目大意:有 N 个字符串,所有的字符串长度不超过 200W 任意俩俩字符串可以自由组合,问组合的字符串是回文串的个数有多少个?   分析:这是一个相当猥琐的字符串处理,因为没有说单个的字符串最少多长 ...

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

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

  4. poj3376 Finding Palindromes【exKMP】【Trie】

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

  5. 字典树 - A Poet Computer

    The ACM team is working on an AI project called (Eih Eye Three) that allows computers to write poems ...

  6. ACM: Gym 100935F A Poet Computer - 字典树

    Gym 100935F A Poet Computer Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%I64d &am ...

  7. Trie树(字典树)(1)

    Trie树.又称字典树,单词查找树或者前缀树,是一种用于高速检索的多叉树结构. Trie树与二叉搜索树不同,键不是直接保存在节点中,而是由节点在树中的位置决定. 一个节点的全部子孙都有同样的前缀(pr ...

  8. poj 3376 Finding Palindromes

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

  9. 019(The XOR Largest Pair)(字典树)

    题目:http://ybt.ssoier.cn:8088/problem_show.php?pid=1472 题目思路:异或是啥呀? 异或就是把两个数字变成位数相同的二进制在同位比较,相同为0,不同为 ...

随机推荐

  1. docker --Nexus仓库

    Nexus 简介 Nexus 是个仓库管理器,目前主要分2大版本:2.X 和 3.X.2.X 主要支持的格式是Maven.P2.OBR.Yum.3.X主要支持的是Docker.NuGet.npm.Bo ...

  2. AISing Programming Contest 2019 翻车记

    A:签到. #include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> ...

  3. bzoj 3289 : Mato的文件管理 (莫队+树状数组)

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=3289 思路: 求区间最小交换的次数将区间变成一个不降序列其实就是求区间逆序对的数量,这 ...

  4. MT【11】对数放缩题

    解答:C 评论:这里讲几个背景知识

  5. 自学Zabbix6.1 Event acknowledgment 事件确认

    自学Zabbix6.1 Event acknowledgment 事件确认 1 概述以往服务器出现报警,运维人员处理完事之后,报警自动取消,但是下一次出现同样一个错误,但是换了一个运维人员,他可能需要 ...

  6. BZOJ 3526: [Poi2014]Card

    3526: [Poi2014]Card Time Limit: 25 Sec  Memory Limit: 64 MBSubmit: 267  Solved: 191[Submit][Status][ ...

  7. pandas 从入门到遗忘

    读取大文件(内存有限): import pandas as pd reader = pd.read_csv("tap_fun_test.csv", sep=',', iterato ...

  8. synchronized的实现原理与应用

    Java代码在编译后会变成Java字节码,字节码被类加载器加载到JVM里,JVM执行字节码,最终需要转化为汇编指令在CPU上执行,Java中所使用的并发机制依赖于JVM的实现和CPU的指令. sync ...

  9. A1095. Cars on Campus

    Zhejiang University has 6 campuses and a lot of gates. From each gate we can collect the in/out time ...

  10. A1097. Deduplication on a Linked List

    Given a singly linked list L with integer keys, you are supposed to remove the nodes with duplicated ...