E. Palisection
time limit per test

2 seconds

memory limit per test

128 megabytes

input

standard input

output

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.

Input

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).

Output

In the only line output the amount of different pairs of two subpalindromes that cross each other. Output the answer modulo 51123987.

Examples
input
4
babb
output
6
input
2
aa
output
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(回文树)的更多相关文章

  1. Palisection(Codeforces Beta Round #17E+回文树)

    题目链接 传送门 题意 给你一个串串,问你有多少对回文串相交. 思路 由于正着做不太好算答案,那么我们考虑用总的回文对数减去不相交的回文对数. 而不相交的回文对数可以通过计算以\(i\)为右端点的回文 ...

  2. 【CF17E】Palisection(回文树)

    [CF17E]Palisection(回文树) 题面 洛谷 题解 题意: 求有重叠部分的回文子串对的数量 所谓正难则反 求出所有不重叠的即可 求出以一个位置结束的回文串的数量 和以一个位置为开始的回文 ...

  3. Codeforces 932G Palindrome Partition - 回文树 - 动态规划

    题目传送门 通往???的传送点 通往神秘地带的传送点 通往未知地带的传送点 题目大意 给定一个串$s$,要求将$s$划分为$t_{1}t_{2}\cdots t_{k}$,其中$2\mid k$,且$ ...

  4. CF17E Palisection(manacher/回文树)

    CF17E Palisection(manacher/回文树) Luogu 题解时间 直接正难则反改成求不相交的对数. manacher求出半径之后就可以差分搞出以某个位置为开头/结尾的回文串个数. ...

  5. Codeforces.GYM100548G.The Problem to Slow Down You(回文树)

    题目链接 \(Description\) 给定两个串\(S,T\),求两个串有多少对相同回文子串. \(|S|,|T|\leq 2\times 10^5\). \(Solution\) 好菜啊QAQ ...

  6. CF17E Palisection(回文树)

    题意翻译 给定一个长度为n的小写字母串.问你有多少对相交的回文子 串(包含也算相交) . 输入格式 第一行是字符串长度n(1<=n<=2*10^6),第二行字符串 输出格式 相交的回文子串 ...

  7. Palindrome Partition CodeForces - 932G 回文树+DP+(回文后缀的等差性质)

    题意: 给出一个长度为偶数的字符串S,要求把S分成k部分,其中k为任意偶数,设为a[1..k],且满足对于任意的i,有a[i]=a[k-i+1].问划分的方案数. n<=1000000 题解: ...

  8. 回文树练习 Part1

    URAL - 1960   Palindromes and Super Abilities 回文树水题,每次插入时统计数量即可. #include<bits/stdc++.h> using ...

  9. 回文树 Palindromic Tree

    回文树 Palindromic Tree 嗯..回文树是个什么东西呢. 回文树(或者说是回文自动机)每个节点代表一个本质不同的回文串. 首先它类似字典树,每个节点有SIGMA个儿子,表示对应的字母. ...

随机推荐

  1. vue TypeError: Cannot read property 'length' of undefined 问题解决思路

    上图中是我在接手一个项目的时候,出现的一个关于数组的 bug,但是从上图来看,其实报错是不清楚的,只能从报错信息上看出来是 /src/page/waybill/waybill_form.vue 这个 ...

  2. server2008服务器IIS7 +PHP5.3出现500错误的排错方法

    Windows7 IIS 500 – 内部服务器错误解决方案 1.解决方法:打开IIS,在全局功能视图中找到“错误页”,双击进去后,看最右边的“操作”下的“编辑功能设置…”,将“错误响应”下的“详细错 ...

  3. JS -判断、监听屏幕横竖屏切换事件

    通过监听window.orientationchange事件,当横竖屏切换事件时触发 <!doctype html> <html> <head> <title ...

  4. web ul li

    <html> <head> <style type="text/css"> ul{float:right} ul li{float:left; ...

  5. C#元祖Tuple的事例

    数组合并了同样类型的对象.而元祖合并了不同类型的对象.元祖起源于函数编程语言(F#) NET Framework定义了8个泛型Tuple(自NET4.0)和一个静态的Tuple类,他们作用元祖的工厂, ...

  6. 156. Merge Intervals【easy】

    Given a collection of intervals, merge all overlapping intervals.   Example Given intervals => me ...

  7. NetBeans 设置code completion/auto pop-up delay

    如果你在Tools>Options>Editor>Code Completion>Language: Java 没有找到设置delay的选项.那就去C盘(如果你用的是Windo ...

  8. HTML5坦克大战(1)绘制坦克

    坦克尺寸如下: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head&g ...

  9. c# 文件操作 txt、xml、ini

    1. txt文件 /// <summary> /// 读文本文件信息 /// </summary> /// <param name="FilePath" ...

  10. The Definitive Guide To Django 2 学习笔记(二) 第二个View 动态内容

    “Hello World”只是简单的展现了Django 基本的工作机制,但它不是动态的网页.第二个View我们将创建一个动态的网页,该页面上将展现当前的时间和日期. 该View需要做两件事,第一,计算 ...