题目大意:有 N 个字符串,所有的字符串长度不超过 200W 任意俩俩字符串可以自由组合,问组合的字符串是回文串的个数有多少个?
 
分析:这是一个相当猥琐的字符串处理,因为没有说单个的字符串最少多长,所以很可能会有这样的情况,200w个字符串,每个字符串长度1,或者1个串,这个串的长度是100w, 为了对付这种猥琐的方式可以用一个长为100w的字符串保存所有的串,然后用另一个数组记录每个字符串所在的区间。匹配的时候可以使用trie因为回文串是两端匹配,所以插入trie的时候可以倒着插入,不过查询的时候会出现两种情况,一种是这个字符串已经匹配完,不过他后面匹配的字符串没有完,另一种是这个字符串匹配完还有剩余长度,不管哪种情况都需要判断一下剩余的串是否是回文串,tire里面的保存后缀,匹配串保存的是前缀。
 
代码如下:
================================================================================================================
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std; const int MAXN = 2e6+;
const int oo = 1e9+; struct Trie
{///字典树的节点
int next[];
int leaf;///以这个节点为终点的叶子节点个数
int count;///后面回文串的数量 void Free()
{
leaf = count = ;
memset(next, false, sizeof(next));
} }trie[MAXN]; int top;///配合字典树使用,top表示没有使用的内存
int start[MAXN], p[MAXN<<];
char MumStr[MAXN], Estr[MAXN<<];
bool suffix[MAXN];///后缀是否是回文串
bool prefix[MAXN];///前缀是否是回文串 void BuildTrie(int n)
{
int p = ; for(int i=start[n+]-; i>=start[n]; i--)
{///把字符串倒插进去
int k = MumStr[i] - 'a'; trie[p].count += prefix[i]; if(trie[p].next[k] == )
{
trie[p].next[k] = ++top;
trie[top].Free();
}
p = trie[p].next[k];
} trie[p].leaf += ;
}
void Manacher(int n)
{
int i, id=, len=; Estr[] = '$'; for(i=start[n]; i<start[n+]; i++)
{
Estr[len++] = '#';
Estr[len++] = MumStr[i]; suffix[i] = false;
prefix[i] = false;
}
Estr[len] = '#';
Estr[len+] = ; for(i=; i<len; i++)
{
p[i] = ; if(p[id]+id > i)
p[i] = min(p[id*-i], p[id]+id-i); while(Estr[ i+p[i] ] == Estr[ i-p[i] ])
p[i]++; if(p[id]+id < p[i]+i)
id = i; if(p[i] == i)
prefix[ start[n]+p[i]- ] = true;
if(p[i]+i- == len)
suffix[ start[n+]-p[i]+ ] = true;
}
}
int Query(int n)
{
int i, p=, sum = ; for(i=start[n]; i<start[n+]; i++)
{
int k = MumStr[i] - 'a'; if(trie[p].next[k] == )
break; p = trie[p].next[k]; if(suffix[i+] || i==start[n+]-)
sum += trie[p].leaf;
} if(i == start[n+])
sum += trie[p].count; return sum;
} int main()
{
int N; while(scanf("%d", &N) != EOF)
{
int i, len; top = ;
trie[].Free(); for(i=; i<=N; i++)
{
scanf("%d%s", &len, MumStr+start[i]);
start[i+] = start[i] + len; Manacher(i);
BuildTrie(i);
} long long ans = ; for(i=; i<=N; i++)
ans += Query(i); printf("%lld\n", ans);
} return ;
}
/**
2
3 abc
4 acba */

最新文章

  1. 马士兵Java视频教程 —— 学习顺序
  2. php案列分享
  3. 错误: java.lang.reflect.InvocationTargetException
  4. J2EE、J2SE、J2ME是什么意思?
  5. freeregex-0.01 使用文档
  6. java输出任意两个日期之间有多少天
  7. fibonacci数列的和取余(2)
  8. SweetAlert2 使用教程
  9. 从扩展方法到匿名方法再到LINQ
  10. C的快速趋向实验 --&gt;
  11. WIN_2003_SP2.iso VMware 不能进行网络访问的处理
  12. HTML特殊符号编码大全
  13. 论山寨手机与Android联姻 【9】SmartPhone的硬件结构
  14. ASP.Net MVC @Html类
  15. 1.1.Core Data是什么(Core Data 应用程序实践指南)
  16. Snapman设计中的思考
  17. 浅谈对ST表的一些理解
  18. P2P视频模块
  19. tp5时间戳转日期的方法
  20. 通过 Ansible 安装 Docker

热门文章

  1. C#和asp.net中链接数据库中 参数的几种传递方法
  2. UIView下使用Animation控制动画
  3. 十四、C# 支持标准查询运算符的集合接口
  4. node 裁剪图片
  5. Flightgear 编译
  6. hash表的建立和查找
  7. jQuery实现公告文字左右滚动的代码。
  8. 一个IP支持多个网站实例(Apache2、Ubuntu相关)
  9. 一个小白对Arguments的理解
  10. Excel等外部程序点击链接会带上IE信息的bug