枚举子串的中心,往两侧扩展,将两侧对应位置的字符交替写下来,得到一个字符串$S$。

若前后长度为$L$的子串循环同构,则在$S$中它们对应长度为$2L$的前缀,需要满足它可以由不超过$2$个偶回文串拼接而成。

有一个结论是,若$S=uv$,其中$uv$都是偶回文串,那么要么$u$是$S$的最长偶回文前缀,要么$v$是$S$的最长偶回文后缀。

证明:

设$S=x_1y_1=x_2y_2=x_3y_3$。

假设结论不成立,那么显然双回文划分数$\geq 3$,设$x_1$为$S$的最长回文前缀,$y_3$是$S$的最长回文后缀,$x_2$和$y_2$都是回文串,则$y_1$和$x_3$都不是回文串。

因为$x_1$是最长回文前缀,所以$|x_1|>|x_2|$,同理$|y_2|<|y_3|$,则$|x_1|>|x_2|>|x_3|$。

................[v.....]

[x1...................][y1....]

[x2..........][y2.............]

[x3.....][y3..................]

设$x_1=x_2v$,那么因为$v$是回文串$y_2$的前缀,所以$v^R$是$y_2$的后缀,也是$y_3$的后缀,因为$y_3$是回文串,所以$v$是$y_3$的前缀,得出$x_3v$是$x_1$的前缀。

因为$x_1$是回文串,$x_2$是$x_1$的前缀,所以$x_2^R$是$x_1$的后缀,又因为$x_2$是回文串,所以$x_2$也是$x_1$的后缀,所以长度$|x_1|-|x_2|=|v|$是$x_1$的一个周期,也是$x_1$的前缀$x_3v$的一个周期。这说明$|v|$也是$v^Rx_3^R$的一个周期,即$x_3^R$是$v^Rv^R...v^Rv^R$的前缀。

因为$v$是回文串$x_1$的后缀,所以$v^R$是$x_1$的前缀,而$|v|$是$x_1$的周期,所以$x_1$是$v^Rv^R...v^Rv^R$的前缀,那么$x_1$的前缀$x_3$也是$v^Rv^R...v^Rv^R$的前缀。

因为$x_3^R$和$x_3$都是$v^Rv^R...v^Rv^R$的前缀,所以$x_3=x_3^R$,即$x_3$是回文串,和假设矛盾。所以结论成立。

通过Manacher预处理出每个位置的最长回文半径$f$,即可求出每个前缀的最长偶回文前缀和最长偶回文后缀,剩下部分可以根据$f$数组$O(1)$判断一个子串是否是回文串。

时间复杂度$O(n^2)$。

#include<cstdio>
const int N=10010;
int n,i,a[N],c[N],s[N],f[N],pre[N],suf[N],ans;
inline int min(int a,int b){return a<b?a:b;}
inline void umin(int&a,int b){a>b?(a=b):0;}
inline void umax(int&a,int b){a<b?(a=b):0;}
inline bool check(int l,int r){
if(l>r)return 1;
return l+r+f[l+r]>r+r;
}
inline void solve(int x){
int i,j,r,p,m=0,len;
for(i=x,j=x+1;i&&j<=n;i--,j++)c[++m]=a[i],c[++m]=a[j];
for(i=1;i<=m;i++)s[i<<1]=c[i],s[i<<1|1]=-1;
s[0]=-2,s[1]=-1,s[len=(m+1)<<1]=-3;
for(r=p=0,f[1]=1,i=2;i<len;i++){
for(f[i]=r>i?min(r-i,f[p*2-i]):1;s[i-f[i]]==s[i+f[i]];f[i]++);
if(i+f[i]>r)r=i+f[i],p=i;
}
for(i=0;i<=m+1;i++)pre[i]=0,suf[i]=len;
for(i=3;i<len;i+=2){
if(f[i]==i)pre[f[i]-1]=f[i]-1;
umin(suf[(i+f[i]-1)>>1],i>>1);
}
for(i=1;i<=m;i++)umax(pre[i],pre[i-1]);
for(i=m;i;i--)umin(suf[i],suf[i+1]);
for(i=0;i<=m;i++)if(suf[i]>=i)suf[i]=0;else suf[i]=(i-suf[i])<<1;
for(i=2;i<=m;i+=2)if(check(pre[i]+1,i)||check(1,i-suf[i]))ans++;
}
int main(){
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
for(i=1;i<n;i++)solve(i);
return printf("%d",ans),0;
}

  

BZOJ4962 : 简单的字符串的更多相关文章

  1. Redis的简单动态字符串实现

    Redis 没有直接使用 C 语言传统的字符串表示(以空字符结尾的字符数组,以下简称 C 字符串), 而是自己构建了一种名为简单动态字符串(simple dynamic string,sds)的抽象类 ...

  2. SQL点滴3—一个简单的字符串分割函数

    原文:SQL点滴3-一个简单的字符串分割函数 偶然在电脑里看到以前保存的这个函数,是将一个单独字符串切分成一组字符串,这里分隔符是英文逗号“,”  遇到其他情况只要稍加修改就好了 CREATE FUN ...

  3. Redis数据结构之简单动态字符串SDS

    Redis的底层数据结构非常多,其中包括SDS.ZipList.SkipList.LinkedList.HashTable.Intset等.如果你对Redis的理解还只停留在get.set的水平的话, ...

  4. 小白的Redis学习(一)-SDS简单动态字符串

    本文为读<Redis设计与实现>的记录.该书以Redis2.9讲解Redis相关内容.请注意版本差异. Redis使用C语言实现,他对C语言中的char类型数据进行封装,构建了一种简单动态 ...

  5. redis_简单动态字符串

    在redis中,C字符串(以'\0'结尾的字符数组)只用在一些无需对字符串值进行修改的地方,比如打印日志.其他情况,redis使用SDS - SimpleDynamicString 简单动态字符串,来 ...

  6. redis 系列3 数据结构之简单动态字符串 SDS

    一.  SDS概述 Redis 没有直接使用C语言传统的字符串表示,而是自己构建了一种名为简单动态字符串(simple dynamic string, SDS)的抽象类型,并将SDS用作Redis的默 ...

  7. 图解Redis之数据结构篇——简单动态字符串SDS

    图解Redis之数据结构篇--简单动态字符串SDS 前言     相信用过Redis的人都知道,Redis提供了一个逻辑上的对象系统构建了一个键值对数据库以供客户端用户使用.这个对象系统包括字符串对象 ...

  8. Redis中的简单动态字符串

    Redis没有直接使用C语言传统的字符串表示(以空字符结尾的字符数组,以下简称C字符串),而是自己构建了一种名为简单动态字符串(simple dynamic string,SDS)的抽象类型,并将SD ...

  9. Redis---SDS(简单动态字符串)

    Redis 没有直接使用 C 语言传统的字符串表示(以空字符结尾的字符数组,以下简称 C 字符串), 而是自己构建了一种名为简单动态字符串(simple dynamic string,SDS)的抽象类 ...

随机推荐

  1. 51 NOd 1459 迷宫游戏 (最短路径)

    1459 迷宫游戏  基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 你来到一个迷宫前.该迷宫由若干个房间组成,每个房间都有一个得分,第一次进入这个房间, ...

  2. OpenCV-Python入门教程4-颜色空间转换

    一.颜色空间转换 import cv2 import numpy as np img = cv2.imread('lena.jpg') # 转换成灰度图 img_gray = cv2.cvtColor ...

  3. javascript OOP(下)(九)

    一.javascript模拟重载 java中根据参数类型和数量的区别来实现重载,javascript弱类型,没有直接的机制实现重载,javascript中参数类型不确定和参数个数任意,通过判断实际传入 ...

  4. 如何访问https的网站?-【httpclient】

    备注:本处代码使用groovy和httpclient4.3作为例子进行讲述 在普通方式下,当使用httpclient进行访问某个网站时,大致使用如下的代码进行访问: CloseableHttpClie ...

  5. linux 软中断过高性能优化案例

    案例如下: 发现cpu0上的软中断高达50%

  6. Codeforces 425E Sereja and Sets dp

    Sereja and Sets 我们先考虑对于一堆线段我们怎么求最大的不相交的线段数量. 我们先按 r 排序, 然后能选就选. 所以我们能想到我们用$dp[ i ][ j ]$表示已经选了 i 个线段 ...

  7. Could not locate executable null\bin\winutils.exe in the Hadoop binaries解决方式 spark运行wordcoult

    虽然可以正常运行,但是会出异常,现给出解决方法. 1.问题:   2.  问题解决: 仔细查看报错是缺少winutils.exe程序. Hadoop都是运行在Linux系统下的,在windows下ec ...

  8. BZOJ3110 [Zjoi2013]K大数查询 树套树 线段树 整体二分 树状数组

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3110 题意概括 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位 ...

  9. 数位dp 模板

    不能有49 #include<bits/stdc++.h> using namespace std; //input by bxd #define rep(i,a,b) for(int i ...

  10. Git branch 出现"HEAD detached at head xxxxx"

    Git branch 出现"HEAD detached at head xxxxx" git branch <your-branch-name> xxxxx      ...