CodeForces 17E Palisection(回文树)
2 seconds
128 megabytes
standard input
standard output
In an English class Nick had nothing to do at all, and remembered about wonderful strings called palindromes. We should remind you that a string is called a palindrome if it can be read the same
way both from left to right and from right to left. Here are examples of such strings: «eye», «pop»,
«level», «aba», «deed»,
«racecar», «rotor», «madam».
Nick started to look carefully for all palindromes in the text that they were reading in the class. For each occurrence of each palindrome in the text he wrote a pair — the position of the beginning and the position of the ending of this occurrence in the text.
Nick called each occurrence of each palindrome he found in the text subpalindrome. When he found all the subpalindromes, he decided to find out how many different pairs among these subpalindromes
cross. Two subpalindromes cross if they cover common positions in the text. No palindrome can cross itself.
Let's look at the actions, performed by Nick, by the example of text «babb». At first he wrote out all subpalindromes:
• «b» — 1..1
• «bab» — 1..3
• «a» — 2..2
• «b» — 3..3
• «bb» — 3..4
• «b» — 4..4
Then Nick counted the amount of different pairs among these subpalindromes that cross. These pairs were six:
1. 1..1 cross with 1..3
2. 1..3 cross with 2..2
3. 1..3 cross with 3..3
4. 1..3 cross with 3..4
5. 3..3 cross with 3..4
6. 3..4 cross with 4..4
Since it's very exhausting to perform all the described actions manually, Nick asked you to help him and write a program that can find out the amount of different subpalindrome pairs that cross. Two subpalindrome pairs are regarded as different if one of the
pairs contains a subpalindrome that the other does not.
The first input line contains integer n (1 ≤ n ≤ 2·106)
— length of the text. The following line contains n lower-case Latin letters (from ato z).
In the only line output the amount of different pairs of two subpalindromes that cross each other. Output the answer modulo 51123987.
4
babb
6
2
aa
2
给你一个串让你求,所有相交的回文子串对的个数
我们可以利用回文树求出以s[i]为结尾的回文子串个数Ai,和以s[i]为开始的的回文串个数Bi
那么不相交的回文子串对就是Ai*sum{Bi+1,Bi+2,Bi+3....Bi+n} {i=1..n-1};
然后用总的回文串对数减去不相交的就是答案。
我们知道利用回文树可以求出以i为结尾的回文串个数,那么以i为开始的,只需要将字符串倒着插入就好了。
另外,这道题目的字符串的长度有2百万,回文树中的next[][]数组,将会内存超限,所以只能用邻接表代替矩阵了
为了对回文树更好的学习,在求所有回文子串和的时候我们可以用两种方式,具体看代码
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <math.h>
#include <stdio.h> using namespace std;
typedef long long int LL;
const int MAX=2*1e6;
const int mod=51123987;
int n;
char str[MAX+5];
int sum[MAX+5];
struct link //next的邻接表
{
int u[MAX+5];int v[MAX+5];
int next[MAX+5];int head[MAX+5];
int tot;
void clear()
{
memset(head,-1,sizeof(head));
tot=0;
}
void clear(int x){head[x]=-1;}
int get(int x,int y)
{
for(int i=head[x];i!=-1;i=next[i])
{
if(u[i]==y)
return v[i];
}
return 0;
}
void insert(int x,int y,int z)
{
u[tot]=y; v[tot]=z;
next[tot]=head[x];
head[x]=tot++;
} };
struct Tree
{
//int next[MAX+5][26];
int fail[MAX+5];//指向当前节点回文串中最长的后缀回文子串
int cnt[MAX+5];//当前节点的回文串一共有多少个
int num[MAX+5];//当前节点为结尾的回文子串的个数
int len[MAX+5];//当前节点的回文串的长度
int s[MAX+5];//字符串
int last;//回文树最后一个节点
int n;
int p;//回文树当前有多少个节点
link next;//邻接表,表示当前节点回文串在两端添加一个字符形成的另一个节点的回文串
int new_node(int x)
{
//memset(next[p],0,sizeof(next[p]));
cnt[p]=0;
next.clear(p);
num[p]=0;
len[p]=x;
return p++;
} void init()
{
next.clear();
p=0;
new_node(0);
new_node(-1);
last=0;
n=0;
s[0]=-1;
fail[0]=1;
} int get_fail(int x)
{
while(s[n-len[x]-1]!=s[n])
x=fail[x];
return x;
} int add(int x)
{
x-='a';
s[++n]=x;
int cur=get_fail(last);
if(!(last=next.get(cur,x)))
{
int now=new_node(len[cur]+2);
fail[now]=next.get(get_fail(fail[cur]),x);
next.insert(cur,x,now);
num[now]=num[fail[now]]+1;
last=now;
}
cnt[last]++;
return num[last];
}
LL Allsum()//求出所有回文子串的数目
{
LL ret=0; for(int i=p-1;i>0;i--)
{
cnt[fail[i]]=(cnt[fail[i]]+cnt[i])%mod; ret=(ret+cnt[i])%mod;
}
return ret;
}
}tree;
int main()
{
scanf("%d",&n);
scanf("%s",str);
tree.init();
sum[n]=0;
for(int i=n-1;i>=0;i--)
sum[i]=(sum[i+1]+tree.add(str[i]))%mod;
tree.init();
LL ans=0;LL res=0;LL res2=0;
for(int i=0;i<=n-1;i++)
{
ans=(ans+(LL)tree.add(str[i])*sum[i+1])%mod;
res2+=tree.num[tree.last];//同样也可以求所有回文子串的数目
}
res=tree.Allsum();
//cout<<res<<" "<<res2<<endl;两个是相等的
ans=(((LL)res*(res-1)/2%mod-ans)%mod+mod)%mod;
printf("%lld\n",ans);
return 0;
}
CodeForces 17E Palisection(回文树)的更多相关文章
- Palisection(Codeforces Beta Round #17E+回文树)
题目链接 传送门 题意 给你一个串串,问你有多少对回文串相交. 思路 由于正着做不太好算答案,那么我们考虑用总的回文对数减去不相交的回文对数. 而不相交的回文对数可以通过计算以\(i\)为右端点的回文 ...
- 【CF17E】Palisection(回文树)
[CF17E]Palisection(回文树) 题面 洛谷 题解 题意: 求有重叠部分的回文子串对的数量 所谓正难则反 求出所有不重叠的即可 求出以一个位置结束的回文串的数量 和以一个位置为开始的回文 ...
- Codeforces 932G Palindrome Partition - 回文树 - 动态规划
题目传送门 通往???的传送点 通往神秘地带的传送点 通往未知地带的传送点 题目大意 给定一个串$s$,要求将$s$划分为$t_{1}t_{2}\cdots t_{k}$,其中$2\mid k$,且$ ...
- CF17E Palisection(manacher/回文树)
CF17E Palisection(manacher/回文树) Luogu 题解时间 直接正难则反改成求不相交的对数. manacher求出半径之后就可以差分搞出以某个位置为开头/结尾的回文串个数. ...
- Codeforces.GYM100548G.The Problem to Slow Down You(回文树)
题目链接 \(Description\) 给定两个串\(S,T\),求两个串有多少对相同回文子串. \(|S|,|T|\leq 2\times 10^5\). \(Solution\) 好菜啊QAQ ...
- CF17E Palisection(回文树)
题意翻译 给定一个长度为n的小写字母串.问你有多少对相交的回文子 串(包含也算相交) . 输入格式 第一行是字符串长度n(1<=n<=2*10^6),第二行字符串 输出格式 相交的回文子串 ...
- Palindrome Partition CodeForces - 932G 回文树+DP+(回文后缀的等差性质)
题意: 给出一个长度为偶数的字符串S,要求把S分成k部分,其中k为任意偶数,设为a[1..k],且满足对于任意的i,有a[i]=a[k-i+1].问划分的方案数. n<=1000000 题解: ...
- 回文树练习 Part1
URAL - 1960 Palindromes and Super Abilities 回文树水题,每次插入时统计数量即可. #include<bits/stdc++.h> using ...
- 回文树 Palindromic Tree
回文树 Palindromic Tree 嗯..回文树是个什么东西呢. 回文树(或者说是回文自动机)每个节点代表一个本质不同的回文串. 首先它类似字典树,每个节点有SIGMA个儿子,表示对应的字母. ...
随机推荐
- C#指南,重温基础,展望远方!(2)程序结构
C# 中的关键组织结构概念包括程序.命名空间.类型.成员和程序集. C# 程序由一个或多个源文件组成. 程序声明类型,而类型则包含成员,并被整理到命名空间中. 类型示例包括类和接口. 成员示例包括字段 ...
- python 去掉字符串的 "
list_name = ["hello", "岚", "许言午", "公司", "赵六", &quo ...
- 统一修改 UINavigationBar backItem
{ UINavigationBar * navigationBar = [UINavigationBar appearance]; //返回按钮的箭头颜色 [navigationBar setTint ...
- 点滴积累【C#】---序列化和反序列化
序列化和反序列化效果图: 序列化和反序列化代码: 需要添加两个命名空间: using System.IO; using System.Runtime.Serialization.Formatters. ...
- WebSocket遇到的一些问题
一 .Nginx配置websocket 为了解决Nginx转发不能进行websocket通信问题 将nginx配置文件添加如下内容: map $http_upgrade $connection ...
- twemproxy源码分析2——守护进程的创建
twemproxy源码中关于守护进程的创建实现得比较标准,先贴出代码来,然后结合一些资料来分析和列举一些实现守护进程的常用方法,不过不得不说twemproxy的实现确实是不错的,注释都写在了代码中,直 ...
- PHP中的正则表达式及模式匹配
PHP中的正则表达式及模式匹配 PHP中对于正则处理文本提供了两种方式,一种是PCRE方式(PCRE库是一个实现了与perl 5在语法和语义上略有差异(详见下文)的正则表达式模式匹配功能的函数集. 当 ...
- Ream的入门使用
一.介绍 Realm是一个不错的手机平台上的数据库,支持多种编程环境,如:Java.Object-C.React Native.Swift.Xamari等. Realm的官网:https://real ...
- JavaScript变量的生命周期
最近看国外经典教材的时候发现JavaScript与熟知的Java,C,C++都不同的特性,其中一个就是变量的生命周期. 1.在JavaScript中,对于for循环中定义的i变量,其生命周期在循环 ...
- Model Binding is not working. MVC3 视图模型绑定不成功
问题出现在POST方法中,当我要将数据提交到后台的时候,绑定的变量值为null 原因是视图中的名称跟Controller中的视图的名称不一致造成的. 假如你视图中的Model采用的是Html.Labe ...