HDU5785 Interesting(Manacher + 延迟标记)
题目
Source
http://acm.hdu.edu.cn/showproblem.php?pid=5785
Description
Alice get a string S. She thinks palindrome string is interesting. Now she wanna know how many three tuple (i,j,k) satisfy 1≤i≤j<k≤length(S), S[i..j] and S[j+1..k] are all palindrome strings. It's easy for her. She wants to know the sum of i*k of all required three tuples. She can't solve it. So can you help her? The answer may be very large, please output the answer mod 1000000007.
A palindrome string is a string that is same when the string is read from left to right as when the string is read from right to left.
Input
The input contains multiple test cases.
Each test case contains one string. The length of string is between 1 and 1000000. String only contains lowercase letter.
Output
For each test case output the answer mod 1000000007.
Sample Input
aaa
abc
Sample Output
14
8
分析
题目大概说给一个字符串,找到其所有子串[i...k]满足它是由两个回文串拼成的,求Σi*k。
官方题解这么说的:
用manacher算法O(n)求出所有的回文半径。有了回文半径后,就可以求出cntL[i]表示以i结尾的回文串的起始位置的和cntR[i]表示以i起始的回文串的结尾位置的和,然后就可以求出答案了,这里要注意奇偶长度回文串的不同处理。复杂度O(n)。
本渣渣看了好久想了好久。。才反应过来x1*y1+x1*y2+x2*y1+x2*y2=(x1+x2)*(y1+y2) 。。这个真反应不过来= =太渣了。。那么只要求出cntL[i]和cntR[i],Σ(cntL[i]*cntR[i+1])就是要的答案了。
本渣渣又看了好久想了好久。。才想到怎么在O(n)求出cntL[i]和cntR[i]。。
- 首先,跑一下Manacher就能知道每个位置向左和向右最多能延伸的长度
比如中间位置是i(回文串是奇数的情况,偶数同理。另外先不管跑Manacher前插入的特殊字符,因为也同理。。),p[i]表示Manacher求得的延伸半径。
- 那么[i-p[i]+1, i+p[i]-1]就是回文串,故cntL[i+p[i]-1]就该加上i-p[i]+1;
- 而[i-p[i]+2, i+p[i]-2]也是回文串,cntL[i+p[i]-2]就该加上i-p[i]+2…………
总之可以知道这个就相当于,对于cntL数组要在[i, i+p[i]-1]区间上依次加上一个末项为i-p[i]+1且公差为-1的等差数列,cntR也是同理的这儿同样就不说了。
- 那么现在问题就是怎么对区间更新,让区间[L,R]加上一个首项k公差-1的等差数列,这些更新操作完成后要进行单点的查询,而且整个的时间复杂度要为O(n)。
区间更新自然就联想到延迟标记。即,更新操作就用O(1)打打标记,所有更新操作完成后,从左往右O(n)遍历过去,把标记传递过去,并更新真实的值。
- 那么打什么标记?
首先能想到有一个加标记sumtag,表示这个数需要加多少。对于让区间[L,R]加上一个首项k公差-1的等差数列,就让sumtag[L]+=k,然后传递标记中访问到L时把sumtag[L]加到真实的值里,并把标记下传,即sumtag[L+1]+=sumtag[L]-1。不过考虑到多个区间修改有叠加,那么应该还要开几个数组记录各个点有多少个更新操作,sumcnt,那么下传也就要改成sumtag[L+1]+=sumtag[L]-sumcnt[L],另外sumcnt也要传递下去,即sumcnt[L+1]+=sumcnt[L]。
不过这样还不够,因为这么传递会一直传递到数组尾巴,也就是说相当于更新了[L,MAXN]区间,而我们要的是[L,R]区间的更新,多更新了[R+1,MAXN]这个区间,而这个区间显然也是加上了一个等差数列!所以,考虑再用一个标记,减标记subtag,表示区间需要减的数,对于多更新的只要在subtag[R+1]这儿打上个标记就OK了!这个与sumtag是一样的,最后遍历标记下传的同时减去subtag的值即可,当然也需要subcnt。
于是这题就能这么解决了。。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 1111111 char s[MAXN<<1];
int p[MAXN<<1];
void manacher(){
int mx=0,id;
for(int i=1;s[i];++i){
if(mx>i) p[i]=min(p[2*id-i],mx-i);
else p[i]=1;
for(;s[i+p[i]]==s[i-p[i]];++p[i]);
if(p[i]+i>mx){
mx=p[i]+i;
id=i;
}
}
} char str[MAXN]; long long val[2][MAXN];
long long addtag[2][MAXN],addcnt[2][MAXN],subtag[2][MAXN],subcnt[2][MAXN];
void update(int flag,int l,int r,int k){
addtag[flag][l]+=k; addtag[flag][l]%=1000000007;
++addcnt[flag][l];
subtag[flag][r+1]+=k-r+l; subtag[flag][r+1]%=1000000007;
++subcnt[flag][r];
}
void pushdown(){
for(int i=1; str[i]; ++i){
if(addcnt[0][i]){
val[0][i]+=addtag[0][i]; val[0][i]%=1000000007;
addtag[0][i+1]+=addtag[0][i]-addcnt[0][i]; addtag[0][i+1]%=1000000007;
addcnt[0][i+1]+=addcnt[0][i];
}
if(subcnt[0][i]){
val[0][i]-=subtag[0][i]; val[0][i]%=1000000007;
subtag[0][i+1]+=subtag[0][i]-subcnt[0][i]; subtag[0][i+1]%=1000000007;
subcnt[0][i+1]+=subcnt[0][i];
}
if(addcnt[1][i]){
val[1][i]+=addtag[1][i]; val[1][i]%=1000000007;
addtag[1][i+1]+=addtag[1][i]-addcnt[1][i]; addtag[1][i+1]%=1000000007;
addcnt[1][i+1]+=addcnt[1][i];
}
if(subcnt[1][i]){
val[1][i]-=subtag[1][i]; val[1][i]%=1000000007;
subtag[1][i+1]+=subtag[1][i]-subcnt[1][i]; subtag[1][i+1]%=1000000007;
subcnt[1][i+1]+=subcnt[1][i];
}
}
} int main(){
while(~scanf("%s",str+1)){
s[0]='$';
int i=1;
for(;str[i];++i){
s[(i<<1)-1]='#';
s[i<<1]=str[i];
}
s[(i<<1)-1]='#';
s[i<<1]=0;
manacher(); memset(val,0,sizeof(val));
memset(addtag,0,sizeof(addtag));
memset(addcnt,0,sizeof(addcnt));
memset(subtag,0,sizeof(subtag));
memset(subcnt,0,sizeof(subcnt)); for(int i=1; s[i]; ++i){
if(i&1){
if(p[i]/2==0) continue;
update(0,i/2-p[i]/2+1,i/2,i/2+p[i]/2);
update(1,i/2+1,i/2+p[i]/2,i/2);
}else{
update(0,i/2-p[i]/2+1,i/2,i/2+p[i]/2-1);
update(1,i/2,i/2+p[i]/2-1,i/2);
}
}
pushdown(); long long ans=0;
for(int i=1; str[i]&&str[i+1]; ++i){
ans+=val[1][i]*val[0][i+1];
ans%=1000000007;
}
if(ans<0) ans+=1000000007;
printf("%I64d\n",ans);
}
return 0;
}
HDU5785 Interesting(Manacher + 延迟标记)的更多相关文章
- HDU 5785 Interesting manacher + 延迟标记
题意:给你一个串,若里面有两个相邻的没有交集的回文串的话,设为S[i...j] 和 S[j+1...k],对答案的贡献是i*k,就是左端点的值乘上右端点的值. 首先,如果s[x1....j].s[x2 ...
- 多校1005 HDU5785 Interesting (manacher)
// 多校1005 HDU5785 Interesting // 题意:给你一个串,求相邻两个回文串左边端点*右边端点的和 // 思路:马拉车算出最长回文半径,求一个前缀和,既得到每个点对答案的贡献. ...
- FZU 2171(线段树的延迟标记)
题意:容易理解. 分析:时隔很久,再一次写了一道线段树的代码,之前线段树的题也做了不少,包括各种延迟标记,但是在组队分任务之后,我们队的线段树就交给了另外一个队友在搞, 然后我就一直没去碰线段树的题了 ...
- [HDOJ4578]Transformation(线段树,多延迟标记)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4578 四种操作:查询.加法.乘法.改数.应该是需要维护三个lazy标记,然后就是套路了.查询是区间内所 ...
- 杭电 HDU ACM 1698 Just a Hook(线段树 区间更新 延迟标记)
欢迎"热爱编程"的高考少年--报考杭州电子科技大学计算机学院 Just a Hook Time Limit: 4000/2000 MS (Java/Others) Memor ...
- [uva11992]Fast Matrix Operations(多延迟标记,二维线段树,区间更新)
题目链接:https://vjudge.net/problem/UVA-11992 题意:n*m的矩阵,每次对一个子矩阵操作,有三种操作:加x,设置为x,查询.查询返回子矩阵和.最小值.最大值 n很小 ...
- codevs 1082 线段树练习 3 区间更新+延迟标记
题目描述 Description 给你N个数,有两种操作: 1:给区间[a,b]的所有数增加X 2:询问区间[a,b]的数的和. 输入描述 Input Description 第一行一个正整数n,接下 ...
- Tree(树链剖分+线段树延迟标记)
Tree http://poj.org/problem?id=3237 Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 12 ...
- 【左偏树+延迟标记+拓扑排序】BZOJ4003-城池攻占
[题目大意] 有n个城市构成一棵树,除1号城市外每个城市均有防御值h和战斗变化参量a和v. 现在有m个骑士各自来刷副本,每个其实有一个战斗力s和起始位置c.如果一个骑士的战斗力s大于当前城市的防御值h ...
随机推荐
- linux安装软件
安装方式一: RPM包安装 安装方式二:yum包安装 安装方式三:源码包安装 安装方式四:脚步安装包 视频教程
- Redis 数据持久化(一)
Redis的模块化开发设计的还是相当不错的,在Bio.h和Bio.c文件中定义了一个多线程的文件任务处理模块,在添加和处理任务的时候使用互斥锁和条件变量进行的同步,而且本身也支持多线程,这个模块的支持 ...
- Android手绘效果实现
效果图 原理 大概介绍一下实现原理.首先你得有一张图(废话~),接下来就是把这张图的轮廓提取出来,轮廓提取算法有很多,本人不是搞图像处理的,对图像处理感兴趣的童鞋可以查看相关资料.如果你有好的轮廓提取 ...
- VS2012/2013 停止调试后,无法刷新页面
- EasyUi – 5.修改$.messager.show() 弹出窗口在浏览器顶部中间出现
由于在easyui中$.messager.show() 只有一种弹出方式(在浏览器的或下角弹出),我最近在做一个项目的时候需要在浏览器的顶部中间出现.由于自己写花那么多的时间,所以就去修改了原码(不推 ...
- Oracle Redo Log
http://blog.itpub.net/27039319/viewspace-2120623/ 11.2和11.2以下的区别:http://blog.itpub.net/27039319/view ...
- HashMap在并发下可能出现的问题分析
我们都知道,HashMap在并发环境下使用可能出现问题,但是具体表现,以及为什么出现并发问题,可能并不是所有人都了解,这篇文章记录一下HashMap在多线程环境下可能出现的问题以及如何避免. 在分析H ...
- SQL的一切常用函数展示
练习了一下, 用时再慢慢看吧. SHOW WARNINGS; SELECT quote(text_fld) FROM string_tbl; ), 'n'); SELECT ASCII('ö'); S ...
- 11g Physical Standby配置
一,准备 Database DB_UNIQUE_NAME Oracle Net Service Name Primary PROD PROD Physical standby PRODDG PRO ...
- 声明replicated属性之后我编译不通过的问题