传送门:POJ - 3376

题意:给你n个字符串,两两结合,问有多少个是回文的;

题解:这个题真的恶心,我直接经历了5种错误类型 : ) ... 因为卡内存,所以又把字典树改成了指针版本的。

字符串s与字符串t组合是回文串的情况

1. len(s) > len(t), t的反串是 s 的前缀,且s剩下的部分是回文串 (比如s: abbcb  t: ba

2. len(s) = len(t), s = t 的反串(比如s: abc  t: cba

3. len(s) < len(t), s 是 t 的反串的前缀,且 t 的反串剩下的部分是回文串(比如 s: ba  t: bbcb

用拓展kmp求出每个字符串的最长回文前缀和后缀(分别用原串和反串进行exkmp,用反串和原串进行exkmp就可以求出了)然后用原串建trie,用反串去匹配。

1. 在trie中, 若串在非结点位置匹配完成, 则把该节点往下走有多少个回文串累加到答案。

2. 在trie中, 若在匹配串时遇上在这个结点结束的字符串, 那么看剩下的后缀是否是回文, 若是, 则把在该点结束的字符串数目累加到答案。

将所有的字符串都放在一个数组里,用一个数组记录每个串的起点,这样能节省空间。

如果内存超了不妨看看这个地方 int tree[26]; 是不是开了30,26就过了.....

  1. 1 #include<iostream>
  2. 2 #include<algorithm>
  3. 3 #include<string.h>
  4. 4 #define ll long long
  5. 5 using namespace std;
  6. 6
  7. 7 ///next[i]: T[i]到T[m - 1]与T(模式串)的最长相同前缀长度;
  8. 8 ///extend[i]: S[i]到S[n - 1](原串)与T的最长相同前缀长度。
  9. 9
  10. 10 const int maxn=2000100;
  11. 11 int nt[maxn],ex[maxn],k=1,be[maxn],len[maxn];
  12. 12 bool tmp[maxn][2];
  13. 13 char a[maxn],b[maxn];
  14. 14
  15. 15 struct Node
  16. 16 {
  17. 17 int val;
  18. 18 int color;
  19. 19 int tree[26];
  20. 20 };
  21. 21 Node z[maxn];
  22. 22 int tot, root;
  23. 23
  24. 24 int newnode()
  25. 25 {
  26. 26 z[tot].val = 0;
  27. 27 z[tot].color = 0;
  28. 28 memset(z[tot].tree, -1, sizeof(z[tot].tree));
  29. 29 tot++;
  30. 30 return tot-1;
  31. 31 }
  32. 32
  33. 33 //预处理计算next数组
  34. 34 void GETNEXT(char *str,int len)
  35. 35 {
  36. 36 int i=0,j,po;
  37. 37 nt[0]=len; //初始化nt[0]
  38. 38 while(str[i]==str[i+1]&&i+1<len) i++; //计算nt[1]
  39. 39 nt[1]=i;
  40. 40 po=1; //初始化po的位置
  41. 41 for(i=2;i<len;i++){
  42. 42 if(nt[i-po]+i<nt[po]+po) nt[i]=nt[i-po]; //第一种情况,可以直接得到nt[i]的值
  43. 43 else{ //第二种情况,要继续匹配才能得到nt[i]的值
  44. 44 j=nt[po]+po-i;
  45. 45 if(j<0) j=0; //如果i>po+nt[po],则要从头开始匹配
  46. 46 while(i+j<len&&str[j]==str[j+i]) j++; //计算nt[i]
  47. 47 nt[i]=j;
  48. 48 po=i; //更新po的位置
  49. 49 }
  50. 50 }
  51. 51 }
  52. 52
  53. 53 //计算extend数组
  54. 54 void EXKMP(char *s1,int len,char *s2,int l2,int s,int flag) ///s1的后缀和s2的前缀匹配
  55. 55 {
  56. 56 int i=0,j,po;
  57. 57 GETNEXT(s2,len); //计算子串的next数组
  58. 58 while(s1[i]==s2[i]&&i<l2&&i<len) i++; //计算ex[0]
  59. 59 ex[0]=i;
  60. 60 po=0; //初始化po的位置
  61. 61 for(i=1;i<len;i++){
  62. 62 if(nt[i-po]+i<ex[po]+po) ex[i]=nt[i-po]; //第一种情况,直接可以得到ex[i]的值
  63. 63 else{ //第二种情况,要继续匹配才能得到ex[i]的值
  64. 64 j=ex[po]+po-i;
  65. 65 if(j<0) j=0; //如果i>ex[po]+po则要从头开始匹配
  66. 66 while(i+j<len&&j<l2&&s1[j+i]==s2[j]) j++; //计算ex[i]
  67. 67 ex[i]=j;
  68. 68 po=i; //更新po的位置
  69. 69 }
  70. 70 }
  71. 71 for(int i=0;i<l2;i++)
  72. 72 if(ex[i]+i==l2) tmp[i+s][flag]=1;
  73. 73 }
  74. 74
  75. 75 void insert(char *a,int len,int s)
  76. 76 {
  77. 77 int p=root;
  78. 78 for(int i=0;i<len;i++){
  79. 79 int c=a[i]-'a';
  80. 80 z[p].val+=tmp[i+s][0];
  81. 81 if(z[p].tree[c]==-1) {
  82. 82 z[p].tree[c]=newnode();
  83. 83 }
  84. 84 p=z[p].tree[c];
  85. 85 }
  86. 86 z[p].color++;
  87. 87 }
  88. 88
  89. 89 int query(char *a,int len,int s)
  90. 90 {
  91. 91 int p=root;
  92. 92 ll ans=0;
  93. 93 for(int i=0;i<len;i++){
  94. 94 int c=a[i]-'a';
  95. 95 p=z[p].tree[c];
  96. 96 if(p==-1) break;
  97. 97 if((i<len-1&&tmp[s+i+1][1])||i==len-1) ans+=z[p].color;
  98. 98 }
  99. 99 if(p!=-1) ans+=z[p].val;
  100. 100 return ans;
  101. 101 }
  102. 102
  103. 103 int main()
  104. 104 {
  105. 105 ios::sync_with_stdio(false);
  106. 106 cin.tie(0);
  107. 107 cout.tie(0);
  108. 108 int t;
  109. 109 cin>>t;
  110. 110 int l=0;
  111. 111 tot=0;
  112. 112 root=newnode();
  113. 113 for(int i=0;i<t;i++){
  114. 114 cin>>len[i]>>a+l;
  115. 115 be[i]=l;
  116. 116 l+=len[i];
  117. 117 for(int j=0;j<len[i];j++){
  118. 118 b[j+be[i]]=a[l-1-j];
  119. 119 }
  120. 120 EXKMP(a+be[i],len[i],b+be[i],len[i],be[i],0);
  121. 121 EXKMP(b+be[i],len[i],a+be[i],len[i],be[i],1);
  122. 122 insert(a+be[i],len[i],be[i]);
  123. 123 }
  124. 124 ll ans=0;
  125. 125 for(int i=0;i<t;i++){
  126. 126 ans+=query(b+be[i],len[i],be[i]);
  127. 127 }
  128. 128 cout<<ans<<endl;
  129. 129 return 0;
  130. 130 }

POJ - 3376 Finding Palindromes(拓展kmp+trie)的更多相关文章

  1. poj 3376 Finding Palindromes

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

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

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

  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(manacher求前后缀回文串+trie)

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

  5. POJ 3376 Finding Palindromes (tire树+扩展kmp)

    很不错的一个题(注意string会超时) 题意:给你n串字符串,问你两两匹配形成n*n串字符串中有多少个回文串 题解:我们首先需要想到多串字符串存储需要trie树(关键),然后我们正序插入倒序匹配就可 ...

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

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

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

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

  8. poj3376 Finding Palindromes【exKMP】【Trie】

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

  9. Seek the Name, Seek the Fame POJ - 2752(拓展kmp || kmp)

    题意: 就是求前缀和后缀相同的那个子串的长度  然后从小到大输出 解析: emm...网上都用kmp...我..用拓展kmp做的  这就是拓展kmp板题嘛... 求出extend数组后  把exten ...

随机推荐

  1. JavaScript 获得当前日期+时间

    //直接从项目中copy出来的,亲测可用.function getTodayTime(){ var date = new Date(); var seperator1 = "-"; ...

  2. 【C++】《C++ Primer 》第七章

    第七章 类 一.定义抽象数据类型 类背后的基本思想:数据抽象(data abstraction)和封装(encapsulation). 数据抽象是一种依赖于接口(interface)和实现(imple ...

  3. Python基础语法6-冒泡排序

    用for循环实现冒泡排序(升序): array = [3,2,1]  for i in range(len(array) - 1, 0, -1):  for j in range(0, i):  if ...

  4. 【Software Test】Basic Of ST

    文章目录 Learning Objective Introduction Software Applications Before Software Testing What is testing? ...

  5. C# 请求被中止: 未能创建 SSL/TLS 安全通道。 设置SecurityProtocol无效

    今天为了获取一张图片,用了一段代码: ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateV ...

  6. PW6513高压40V的LDO芯片,SOT89封装

    一般说明 PW6513系列是一款高精度,高输入电压,低静态电流,高速,低具有高纹波抑制的线性稳压器.输入电压高达40V,负载电流为在电压=5V和VIN=7V时高达300mA.该设备采用BCD工艺制造. ...

  7. Centos7.4 小白式安装(初学)

    虚拟机安装Centos7.4系统 适用人群(初学者) 下载Centos7.4镜像 https://pan.baidu.com/s/1NtjfdHV3OWAvfDj5vrR7HQ  提取码:hzzw 虚 ...

  8. 7行代码解决P1441砝码称重(附优化过程)

    先贴上最终代码感受一下: #include <bits/stdc++.h> using namespace std; int i, N, M, wi[21], res = 0; int m ...

  9. UI测试框架

    1. 从上到下共分成4层: 用例层  组件管理层  元素管理层  公共数据层 2. 用例层: 将每条用例使用参数化, 公共参数存储到"公共数据层", 中间参数通过组件层传递 3. ...

  10. pandas模块的使用详解

    为什么学习pandas numpy已经可以帮助我们进行数据的处理了,那么学习pandas的目的是什么呢? numpy能够帮助我们处理的是数值型的数据,当然在数据分析中除了数值型的数据还有好多其他类型的 ...