Palindrome

简要题意: 

我们有一个字符串S,字符串的长度不超过500000。

求满足S[i]=S[2n−i]=S[2n+i−2](1≤i≤n)(n≥2)的子串个数。 

分析:

我们能通过简单的数学知识,得到:

该子串是两个回文串拼在一起的,例如abcbabc中,前5项为一个回文串,后5项有一个回文串。

第n项以及第2*n-1项为回文串的中心。

我们可以用Manacher 求得以每个$i$为中心点的回文串半径len[i]。

求得len[i]后,写一个方程:

令i<j,
1. i+len[i]>=j;
2. j-len[j]<=i;
可以推得:
1. i+1<=j<=i+len[i];
2. j-len[j]<=i

所以,这道题便转化成:

已知一个len[i]数组,求满足上列条件的个数! 

怎么求一个区间内小于一个数x的个数呢?

主席树! 

主席树中记录的是每个数字出现过的个数,区间[1,5]即记录数字[1,5]出现的总次数,

我们主席树类似前缀和的思想,依次往后合并。

最终我们求得的答案为:∑query(root[i+len[i]],x)-query(root[i],x);

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define LL long long
const int N=1000005;
int seg,root[N];
struct segment{int v,ls,rs;}tr[N<<4];
int build(int x,int y)
{
int p=++seg;tr[p].v=0;
if(x<y)
{
int mid=(x+y)>>1;
tr[p].ls=build(x,mid);
tr[p].rs=build(mid+1,y);
}
return p;
}
int update(int pre,int l,int r,int x)
{
int p=++seg;
tr[p]=(segment){tr[pre].v+1,tr[pre].ls,tr[pre].rs};
if(l<r)
{
int mid=(l+r)>>1;
if(x<=mid)tr[p].ls=update(tr[pre].ls,l,mid,x);
else tr[p].rs=update(tr[pre].rs,mid+1,r,x);
}
return p;
}
int query(int p1,int p2,int l,int r,int x)
{
if(x<l)return 0;
if(r<=x)return tr[p1].v-tr[p2].v;
int mid=(l+r)>>1;
int res=query(tr[p1].ls,tr[p2].ls,l,mid,x);
if(mid+1<=x)res+=query(tr[p1].rs,tr[p2].rs,mid+1,r,x);
return res;
}
char S[N],s[N<<1];
int val[N<<1],pos[N];
inline void work()
{
scanf("%s",S);int n=strlen(S);
int k=0,id=0,mx=0;
for(re i=0;i<n;++i)s[++k]='#',s[++k]=S[i];s[0]='!';s[++k]='#';
for(re i=1;i<=k;++i)
{
if(i<mx)val[i]=min(val[id*2-i],mx-i);
else val[i]=1;
while(s[i-val[i]]==s[i+val[i]])val[i]++;
if(i+val[i]>mx)mx=i+val[i],id=i;
}
int MAX=0;
for(re i=2;i<=k;i+=2)
{
int id=(i>>1);
pos[id]=(val[i]>>1)-1;
MAX=max(MAX,id-pos[id]);
} seg=0;root[0]=build(1,MAX);
for(re i=1;i<=n;++i)root[i]=update(root[i-1],1,MAX,i-pos[i]);
LL ans=0;
for(re i=1;i<=n;++i)
if(pos[i])ans+=1ll*query(root[i+pos[i]],root[i],1,MAX,i);
printf("%lld\n",ans);
}
signed main()
{
int T;scanf("%d",&T);
while(T--)work();
}

“向前跑,迎着冷眼和嘲笑”

“失败后郁郁寡欢,那是懦夫的表现”----《追梦赤子心》

热身训练3 Palindrome的更多相关文章

  1. 数位dp & 热身训练7

    数位dp 数位dp是一种计数用的dp,一般就是要统计一段区间$[L,R]$内,满足一定条件的数的个数,或者各个数位的个数. 数位dp使得暴力枚举变为满足一定状态的记忆化,更加优秀. 数位dp常常会考虑 ...

  2. 热身训练4 Article

    Article 在这个学期即将结束时,DRD开始写他的最后一篇文章. DRD使用著名的Macrohard的软件World来写他的文章. 不幸的是,这个软件相当不稳定,它总是崩溃. DRD需要在他的文章 ...

  3. 热身训练4 Eighty seven

    Eighty seven 简要题意: n个卡片,其中第i个卡片的数值为$a[i]$.一共q次询问,每次询问将删去其中3个卡片(可能删除若干相同的卡片)后,问能否选出10个卡片,数值之和等于87. n≤ ...

  4. 热身训练2 The All-purpose Zero

    The All-purpose Zero 简要题意:  长度为n的数组,每个数字为S[i],$0$是一种很神奇的数字,你想要的,它都可以变! 问这个序列的最长上升子序列长度为多少? 分析: 我们将除了 ...

  5. 热身训练2 GCD

    题目描述 简要题意:  n个数字,a1,a2,...,an m次询问(l,r),每次询问需回答 1.gcd(al,al+1,al+2,...,ar);2.gcd(ax,ax+1,ax+2,...,ay ...

  6. 热身训练2 Another Meaning

    题目来源 简要题意: 众所周知,在许多情况下,一个词语有两种意思.比如"hehe",不仅意味着"hehe",还意味着"excuse me". ...

  7. 热身训练1 Calculator

    题目出处:Calculator 简要题意: 你有一个确定的函数,f(x)=+...*...^...,其中共有n个操作,从左到右依次计算. 共有m次询问,我们每次询问,1.会修改f(x)中的操作:2.输 ...

  8. 热身训练1 ping ping ping

    点此进入 题意: 一棵树,n+1 个节点,以0号节点为根,给出端点(a,b),节点a到节点b的路径上,至少有一个点是"坏掉的",求"坏掉的点"最少 分析: St ...

  9. 热身训练1 Problem B. Harvest of Apples

    http://acm.hdu.edu.cn/showproblem.php?pid=6333 题意: 求 C(0,n)+C(1,n)+...+C(m,n) 分析: 这道题,我们令s(m,n) = C( ...

随机推荐

  1. Model 特性

    表 1 AssociatedMetadataTypeTypeDescriptionProvider 通过添加在关联类中定义的特性和属性信息,从而扩展某个类的元数据信息. AssociationAttr ...

  2. SpringBoot-初见

    目录 简单介绍 什么是SpingBoot? 微服务 单体应用架构 微服务架构 怎么构建微服务 第一个SpringBoot程序 官方网站快速构建 IDEA 代码 自动装配(要点) pom.xml 启动器 ...

  3. 将rgb表示方式转换为hex表示方式-------------将hex表示方式转换为rgb表示方式(这里返回rgb数组组合)

      /**  * kevin 2021.1.4  * 将rgb表示方式转换为hex表示方式  * @param {string} rgbColor 传过来的hex格式的颜色  * @returns { ...

  4. C# 加载Word的3种方法

    本次经验内容分享通过C#程序来加载Word文档的3种不同方法.分别是: 1. 加载本地Word文档 2. 以只读模式加载Word文档 3. 从流加载Word [程序环境] Windows 10 Vis ...

  5. Dart简易教程 (1)---数据类型 运算符,类转换换

    从下面开始学习DART编程 以下是一个简单的示例: main(){ var number = 42; print(number);}程序说明,dart是一个强大的脚本类语言,可以不预先定义变量类型 , ...

  6. python 打字小游戏

    最近随便用python的pygame编了这个打字小游戏 只要有字母调到窗口底部就结束 上代码: import pygame.freetype import sys import random pyga ...

  7. [CSP-J2020] 优秀的拆分

    [CSP-J2020] 优秀的拆分 难度:普及- 题目描述 一般来说,一个正整数可以拆分成若干个正整数的和. 例如,1=1,10=1+2+3+4 等.对于正整数 n 的一种特定拆分,我们称它为&quo ...

  8. Java基础(六)——集合

    一.概述 1.介绍 为什么出现集合? 答:面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,对对象进行存储,集合就是存储对象最常用的一种方式. 数组和集合类同是容器,有何不同? ...

  9. Shell系列(8)- 变量与变量分类(1)

    变量命名规则 开头为字符或下划线,名字中间中能有字母.数字和下划线组成; 变量的长度不超过255个字符; 变量名在有效的范围内必须是唯一的; 如再次定义则会替换上一个变量的值 在Bash中,变量的默认 ...

  10. Spring Cloud Gateway 没有链路信息,我 TM 人傻了(中)

    本系列是 我TM人傻了 系列第五期[捂脸],往期精彩回顾: 升级到Spring 5.3.x之后,GC次数急剧增加,我TM人傻了 这个大表走索引字段查询的 SQL 怎么就成全扫描了,我TM人傻了 获取异 ...