寻找三元组(i,j,k),使得(i,j)(j,k)都是回文字串,其中i<=j<k.

可以发现,对于每一位i,只要预处理出来有多少个以i为右端的回文串和以i为左端的回文串。把那些串的另一端的坐标和计算出来就可以了。

然后ans = ∑cntR[i]*cntL[i+1]

这里cntR[i]记录以i为右端的回文串的左端坐标和。cntL[i]同理。

然后这道题的数据范围是1e6,多case。必须要O(n)才能过。

首先用O(n)的Manacher处理每一位的回文半径,之后遍历处理

可以发现这里需要O(n)复杂度给指定区间加上一个等差序列。于是开几个数组维护,空间换时间。

用cnt_add记录加了多少次,add记录首项加了多少,这样从首项往后递推,每次add[i+1] = add[i]-cnt_add[i] cnt_add[i+1] += cnt_add[i] cntL[i] += add[i]

这样可以从首项更新到字符串尾。但是我们要更新一段值,就有一段多加了,于是就再开一个mns记录多加的的值.

比如要更新[l,r] 那么就给mns[r+1]置为add[r+1]时的值。这样就可以把多加的抵消了。同时也要维护一个cnt_mns记录次数。

最后还要注意分回文长度奇偶讨论。

//坑了好久的题。最开始想到了用树状数组维护cnt,成段更新,然而卡log。

 #include <cstdio>
#include <ctype.h>
#include <cstring>
#include <algorithm> #define LL long long
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define root 1,N,1
using namespace std; const int maxn = 1e6+;
const LL MOD = 1e9+; char Ma[*maxn];
int Mp[*maxn];
void update(LL &x,LL d)
{
x += d;
if(x >= MOD) x -= MOD;
if(x < ) x += MOD;
} void Manacher(char s[],int len)
{
memset(Mp,,sizeof Mp);
int l = ;
Ma[l++] = '$';
Ma[l++] = '#';
for(int i=;i<len;i++)
{
Ma[l++] = s[i];
Ma[l++] = '#';
}
Ma[l] = ;
int mx = ,id = ;
for(int i=;i<l;i++)
{
Mp[i] = mx > i ? min(Mp[*id-i],mx-i) : ;
while(Ma[i+Mp[i]] == Ma[i-Mp[i]] ) Mp[i]++;
if(i + Mp[i] > mx)
{
mx = i+Mp[i];
id = i;
}
}
} char line[maxn];
int p[maxn];
LL cntL[maxn],cntR[maxn];
LL add[maxn],mns[maxn];
LL cnt_add[maxn],cnt_mns[maxn]; void init()
{
memset(cnt_mns,,sizeof cnt_mns);
memset(cnt_add,,sizeof cnt_add);
memset(add,,sizeof add);
memset(mns,,sizeof mns);
} LL ans = ;
void solve(int len)
{
init();
for(int i=;i<*len+;i++)
{
int tmp = Mp[i];
if(Ma[i] == '#')
{
int cur = i/+,L = (i-tmp)/+, R = (i+tmp)/-,r = (tmp-)/;
update(add[L],R);
update(mns[cur],R-r);
cnt_add[L] ++;
cnt_mns[cur]++;
}else
{
int cur = i/,L = (i-tmp)/+, R = (i+tmp)/-,r = +(tmp-)/;
update(add[L],R);
update(mns[cur+],R-r);
cnt_add[L] ++;
cnt_mns[cur+]++;
}
}
for(int i=;i<=len;i++)
{
update(cntL[i],add[i]-mns[i]);
update(add[i+],add[i]-cnt_add[i]);
update(mns[i+],mns[i]-cnt_mns[i]);
update(cnt_add[i+],cnt_add[i]);
update(cnt_mns[i+],cnt_mns[i]);
} init();
for(int i=;i<*len+;i++)
{
int tmp = Mp[i];
if(Ma[i] == '#')
{
int cur = i/+,L = (i-tmp)/+, R = (i+tmp)/-,r = (tmp-)/;
add[cur] += cur-;
mns[R+] += cur - r - ;
cnt_add[cur] ++;
cnt_mns[R+] ++;
}else
{
int cur = i/,L = (i-tmp)/+, R = (i+tmp)/-,r = +(tmp-)/;
add[cur] += cur;
mns[R+] += cur-r;
cnt_add[cur] ++;
cnt_mns[R+] ++;
}
}
for(int i=;i<=len;i++)
{
update(cntR[i],add[i]-mns[i]);
update(add[i+],add[i]-cnt_add[i]);
update(mns[i+],mns[i]-cnt_mns[i]);
update(cnt_add[i+],cnt_add[i]);
update(cnt_mns[i+],cnt_mns[i]);
}
ans = ;
for(int i=;i<=len;i++)
{
update(ans,(cntR[i]*cntL[i+])%MOD);
}
} int main()
{
//freopen("1005.in","r",stdin);
while(true)
{
char c;
int len = ;
while((c = getchar()) && isalpha(c))
{
line[len++] = c;
}
if(c == EOF) break;
Manacher(line,len); memset(cntL,,sizeof cntL);
memset(cntR,,sizeof cntR);
solve(len);
printf("%I64d\n",(ans+MOD) % MOD);
}
}

多校#5-1005-Instring-HDU5785-manacher+维护的更多相关文章

  1. HDU5785 manacher+差分数组

    用manacher算法O(n)求出所有的回文半径.有了回文半径后,就可以求出L[i]表示以i结尾的回文串的起始位置的和R[i]表示以i起始的回文串的结尾位置的和,然后就可以求出答案了,这里要注意奇偶长 ...

  2. 2019湘潭校赛 E(答案区间维护)

    题目传送 思路是始终维护西瓜数量的区间,即L代表目前可以达到的最少的,R是最多的,然后判断一下. #include <bits/stdc++.h> using namespace std; ...

  3. HDU 4690 EBCDIC (2013多校 1005题 胡搞题)

    EBCDIC Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others)Total Su ...

  4. HDU 6695 Welcome Party (贪心)

    2019 杭电多校 10 1005 题目链接:HDU 6695 比赛链接:2019 Multi-University Training Contest 10 Problem Description T ...

  5. HDU 6628 permutation 1 (暴力)

    2019 杭电多校 5 1005 题目链接:HDU 6628 比赛链接:2019 Multi-University Training Contest 5 Problem Description A s ...

  6. 扩展kmp 学习笔记

    学习了一下这个较为冷门的知识,由于从日报开始看起,还是比较绕的-- 首先定义 \(Z\) 函数表示后缀 \(i\) 与整个串的 \(lcp\) 长度 一个比较好的理解于实现方式是类似于 \(manac ...

  7. 后缀自动机(SAM)+广义后缀自动机(GSA)

    经过一顿操作之后竟然疑似没退役0 0 你是XCPC选手吗?我觉得我是! 稍微补一点之前丢给队友的知识吧,除了数论以外都可以看看,为Dhaka和新队伍做点准备... 不错的零基础教程见 IO WIKI ...

  8. 多校1005 HDU5785 Interesting (manacher)

    // 多校1005 HDU5785 Interesting // 题意:给你一个串,求相邻两个回文串左边端点*右边端点的和 // 思路:马拉车算出最长回文半径,求一个前缀和,既得到每个点对答案的贡献. ...

  9. HDU 5371 (2015多校联合训练赛第七场1003)Hotaru&#39;s problem(manacher+二分/枚举)

    pid=5371">HDU 5371 题意: 定义一个序列为N序列:这个序列按分作三部分,第一部分与第三部分同样,第一部分与第二部分对称. 如今给你一个长为n(n<10^5)的序 ...

随机推荐

  1. python2中reload(sys)后设置编码

    python在安装时,默认的编码是ascii,当程序中出现非ascii编码时,python的处理常常会报这样的错UnicodeDecodeError: 'ascii' codec can't deco ...

  2. struts2的基本使用

    struts2在web中当作前端控制器,接收来自页面的请求,使用过滤器拦截模式对请求进行拦截并交给相应配置的action类处理. 所以在web中使用最重要的是struts2的核心过滤器StrutsPr ...

  3. CodeForces - 1051D-简单DP

    这个题叫问给一个2*N的方块,你可以在每一个上填任意黑或者白两种,假设颜色相同的并且有公共边的就被认为是一块,问组成K块有多少种方案. 这题开始感觉无从下手,像组合数学又不像的,其实这个题的关键在于, ...

  4. from bs4 import BeautifulSoup 报错

    一: BeautifulSoup的安装: 下载地址:https://www.crummy.com/software/BeautifulSoup/bs4/download/4.6/ 下载后,解压缩,然后 ...

  5. 14-Requests+正则表达式爬取猫眼电影

    '''Requests+正则表达式爬取猫眼电影TOP100''''''流程框架:抓去单页内容:利用requests请求目标站点,得到单个网页HTML代码,返回结果.正则表达式分析:根据HTML代码分析 ...

  6. transfer.sh:通过命令行简单的创建文件分享

    简介 通过一个命令,就可以在终端上,将文件加密传输到远程服务器,提供对外文件共享的功能. transfer.sh这是一个我常用的.可以在终端上使用的文件共享服务,可以在某些方面替代sz或者scp命令. ...

  7. 把玩Alpine linux(一):安装

    导读 Alpine Linux是一个面向安全应用的轻量级Linux发行版.它采用了musl libc和busybox以减小系统的体积和运行时资源消耗,同时还提供了自己的包管理工具apk.Alpine ...

  8. 各种jar包

    springframework下载地址:http://maven.springframework.org/release/org/springframework/spring/ commons开头的j ...

  9. Vue基本使用和指令集

    Vue的使用 一.安装 对于新手来说,强烈建议大家使用<script>引入: 二. 引入vue.js文件 我们能发现,引入vue.js文件之后,Vue被注册为一个全局的变量,它是一个构造函 ...

  10. Is-a

    在知识表示.面向对象程序设计与面向对象设计的领域里, is-a(英语:subsumption,包含架构)指的是类的父子继承关系, 例如类D是另一个类B的子类(类B是类D的父类). 换句话说,通常&qu ...