寻找三元组(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. .Net外包篇:我是如何看待外包的

    前言 从工作至今,我在工作之余大大小小接了六次外包,不多不少,虽然没有为我带来很大收益,但也让我开拓了人脉,接触了不少知识,锻炼了全栈开发能力. 菜鸟时代 第一家客户(成功) 我接的第一个外包是为一家 ...

  2. 作为一个.NET开发者,怎么看待和选择层出不穷的新技术,新架构?

    经常在一些技术社区看到这些的问题,一个.NET开发者去求职,看到应聘的公司的技术栈还是比较老的ASP.NET WEBFORM的时候,希望了解未来会否使用ASP.NET MVC的时候,没有获得肯定答复, ...

  3. tkinter python(图形开发界面)

    Tkinter模块("Tk 接口")是Python的标准Tk GUI工具包的接口.Tk和Tkinter可以在大多数的Unix平台下使用,同样可以应用在Windows和Macinto ...

  4. OO博客作业2:第5-7周作业总结

    (1)从多线程的协同和同步控制方面,分析和总结自己三次作业来的设计策略及其变化. 第5次作业:多线程电梯 基本照搬了课件上“生产者-消费者”模型的设计策略,将InputHandler设计为生产者线程, ...

  5. 学习用Node.js和Elasticsearch构建搜索引擎(1):了解并运行Elasticsearch

    1.学习Elasticsearch概述. 了解Elasticsearch是什么?能做什么?可以查一下elasticsearch.lucene等的相关介绍,另外也可以查查资料比较一下其它的搜索引擎sph ...

  6. UnderWater+SDN论文之二

    ---- Software-defined underwater acoustic networking platform and its applications source: Ad Hoc Ne ...

  7. Python IO模型

    这篇博客是本人借鉴一些大神的博客并结合自己的学习过程写下的. 事件驱动模型 事件驱动模型是一种编程范式,这里程序的执行流由外部事件来决定.它的特点是包含一个事件循环,当外部事件发生时,不断从队列里取出 ...

  8. 每周分享之cookie详解

    本章从JS方向讲解cookie的使用.(实质上后端代码也是差不多用法,无非读取和设置两块) 基本用法:document.cookie="username=pengpeng"; 修改 ...

  9. 对于vue和react“页面间”传递数据的理解误区

    前言 如果我们想要实现多个标签页之间的通信,可以使用localStorage.cookie等,但是能不能用vue或react呢? 结论 答案是NO,因为vue和react虽然可以在“多个”页面之间传递 ...

  10. HashMap深度解析(转载)

    原文地址:http://blog.csdn.net/ghsau/article/details/16890151 实现原理:用一个数组来存储元素,但是这个数组存储的不是基本数据类型.HashMap实现 ...