题意:给你一个串,若里面有两个相邻的没有交集的回文串的话,设为S[i...j] 和 S[j+1...k],对答案的贡献是i*k,就是左端点的值乘上右端点的值。

首先,如果s[x1....j]、s[x2....j]、s[x3....j]....s[xn....j]、是回文串,而且s[j+1...y1]、s[j+1...y2]、s[j+1...y3]、也是回文串,那么这些串对答案的贡献一共就是(x1+x2+...+xn)*(y1+y2+....+yn)

所以想到了用cntL[i]表示:以i这个字符为结尾的回文串的左端点之和,cntR[i]表示:以i这个字符为开始的回文串的右端点之和。

所以答案就是for i=1 to lenstr-1  ans += cntL[i]*cntR[i+1];

通俗点说吧,根据manacher,p[i]就表示以i这个字符为中心的回文串的半径长度,所以有s[i-p[i]...i+p[i]]是一个回文串

所以cntL[i+p[i]]就要加上i-p[i],然后因为s[i-p[i]+1...i+p[i]-1]也是一个回文串,所以cntL[i+p[i]-1]就要加上i-p[i]+1等等之类的。所以就是在[i..i+p[i]]这个区间上,依次加上 i、i-1、i-2、.....i-p[i],这样一个公差为-1的等差数列。这个可以用延迟标记来做

先看简单的,在[L,R]上加上一个数val,我们只需要cnt[L] += val; cnt[R+1] -= val;   然后O(n)扫描,即可得到这个数组的所有值。但是现在是等差数列呢?其实是差不多的,只不过要开多一个数组而已。

首先,如果是在[begin,end]上加上一个以val为首相的等差数列,可以这样考虑。首先cnt[begin] += val;然后可以算出结束的时候的值是多少把?cnt[end+1] -= calc_end_val;即可。然后中间的公差,因为可能有叠加现象,我们要开多个数组subL[i]表示这个位置有多少个-1,这个subL[i]就像一开始的最简单的这样传递下去即可。就是subL[begin] += 1; subL[end+1] -= 1;

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include<stack>
#include <string>
const int maxn = +;
const int MOD = ;
int cntL[maxn],cntR[maxn];
int subL[maxn],subR[maxn];
char str[maxn<<];
int p[maxn<<];
void addL (int begin,int end,int val)
{
if (end<begin) return ;
cntL[begin] += val;
cntL[end+] -= begin-end+val;
subL[begin+]++;
subL[end+]--; cntL[begin] %= MOD;
cntL[end+] = (cntL[end+]+MOD)%MOD;
subL[begin+]%=MOD;
subL[end+]=(subL[end+]+MOD)%MOD;
return ;
}
void addR (int begin,int end,int val)
{
if (end<begin) return ;
cntR[begin] += val;
cntR[end+] -= begin-end+val;
subR[begin+]++;//记录有多少个数列覆盖的,记录公差
subR[end+]--; cntR[begin] %= MOD;
cntR[end+] = (cntR[end+]+MOD)%MOD;
subR[begin+]%=MOD;
subR[end+]=(subR[end+]+MOD)%MOD;
return ;
}
int manacher (char str[],int lenstr)
{
str[]='*';
for (int i=lenstr;i>=;i--)
{
str[i+i+]=str[i+];
str[i+i+]='#';
}
int id=,maxlen=;
for (int i=;i<=*lenstr+;i++)
{
if (p[id]+id>i)
{
p[i]=min(p[id]+id-i,p[*id-i]);
}
else p[i]=;
while (str[i+p[i]] == str[i-p[i]]) ++p[i];
if (p[id]+id<p[i]+i) id=i;
maxlen=max(maxlen,p[i]);
}
return maxlen-;
} void init_arr(int gg)
{
for (int i=;i<=gg;++i)
{
subL[i] += subL[i-];
cntL[i] += cntL[i-]-subL[i]; subR[i] += subR[i-];
cntR[i] += cntR[i-]-subR[i]; subL[i] %= MOD; subR[i] %= MOD;
cntL[i]=(cntL[i]+MOD)%MOD; cntR[i]=(cntR[i]+MOD)%MOD;
}
return ;
}
void init ()
{
memset(cntL,,sizeof cntL); memset(cntR,,sizeof cntR);
memset(subL,,sizeof subL); memset(subR,,sizeof subR);
return ;
}
void work ()
{
init();
int lenstr = strlen(str+);
manacher(str,lenstr);
for (int i=;i<=*lenstr+;++i)
{
int len = p[i]-;
if (len==) continue;
if (i&) //'#'所在位置
{
int pos = i/;//截断
//len必须是偶数
int t = len/;
int begin = pos-t+; //这些细节要慢慢算啦,慢慢推公式
int end = t+pos;
addL(pos+,end,pos);
addR(begin,pos,end);
}
else //字母所在位置
{
int pos = i/;
len--;
len/=;
int begin = pos-len;
int end = pos+len;
addL(pos,end,pos);
addR(begin,pos,end);
}
}
init_arr(lenstr);
LL ans = ;
for (int i=;i<=lenstr-;++i)
{
ans += 1LL*cntL[i]*cntR[i+];
ans %= MOD;
}
printf ("%I64d\n",ans);
return ;
}
int main ()
{
#ifdef local
freopen("data.txt","r",stdin);
#endif
while(scanf("%s",str+)!=EOF) work();
return ;
}

HDU 5785 Interesting manacher + 延迟标记的更多相关文章

  1. HDU5785 Interesting(Manacher + 延迟标记)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5785 Description Alice get a string S. She think ...

  2. HDU 5785 Interesting

    题目: 大概说给一个字符串,找到其所有子串[i...k]满足它是由两个回文串拼成的,求Σi*k. 分析: 用val[1][i]表示以i结尾的回文串的起始位置的和val[0][i]表示以i起始的回文串的 ...

  3. HDU 4391 Paint The Wall(分块+延迟标记)

    Paint The Wall Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  4. 杭电 HDU ACM 1698 Just a Hook(线段树 区间更新 延迟标记)

    欢迎"热爱编程"的高考少年--报考杭州电子科技大学计算机学院 Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memor ...

  5. HDU 3468:A Simple Problem with Integers(线段树+延迟标记)

    A Simple Problem with Integers Case Time Limit: 2000MS Description You have N integers, A1, A2, ... ...

  6. [HDOJ4578]Transformation(线段树,多延迟标记)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4578 四种操作:查询.加法.乘法.改数.应该是需要维护三个lazy标记,然后就是套路了.查询是区间内所 ...

  7. FZU 2171(线段树的延迟标记)

    题意:容易理解. 分析:时隔很久,再一次写了一道线段树的代码,之前线段树的题也做了不少,包括各种延迟标记,但是在组队分任务之后,我们队的线段树就交给了另外一个队友在搞, 然后我就一直没去碰线段树的题了 ...

  8. [uva11992]Fast Matrix Operations(多延迟标记,二维线段树,区间更新)

    题目链接:https://vjudge.net/problem/UVA-11992 题意:n*m的矩阵,每次对一个子矩阵操作,有三种操作:加x,设置为x,查询.查询返回子矩阵和.最小值.最大值 n很小 ...

  9. codevs 1082 线段树练习 3 区间更新+延迟标记

    题目描述 Description 给你N个数,有两种操作: 1:给区间[a,b]的所有数增加X 2:询问区间[a,b]的数的和. 输入描述 Input Description 第一行一个正整数n,接下 ...

随机推荐

  1. 【转】 Pro Android学习笔记(七三):HTTP服务(7):AndroidHttpClient

    文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件,转载须注明出处:http://blog.csdn.net/flowingflying/ 不知道此文是否是这个系列中最短的一篇.我们 ...

  2. css中的块级和内联元素

    块级元素: 首先说明display是块级元素,会单独站一行,如 代码: <!DOCTYPE html> <html> <head lang="en"& ...

  3. 人物-IT-任正非:任正非

    ylbtech-人物-IT-任正非:任正非 任正非,祖籍浙江省浦江县,1944年10月25日出生于贵州省安顺市镇宁县.华为技术有限公司主要创始人兼总裁. 1963年就读于重庆建筑工程学院(现已并入重庆 ...

  4. Java常见设计模式之单例模式

         1.何为单例模式? 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类.通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的 ...

  5. MODBUS TCP和MODBUS RTU的差别

    TCP和RTU协议非常类似, MBAP Header长度共7个字节,分别为Transaction identifier(事务标识符),Protocol identifier(协议标识符),Length ...

  6. java基础知识(6)---抽象类与接口

    抽象类: abstract抽象:不具体,看不明白.抽象类表象体现.在不断抽取过程中,将共性内容中的方法声明抽取,但是方法不一样,没有抽取,这时抽取到的方法,并不具体,需要被指定关键字abstract所 ...

  7. python 基础 字典生成式

    dict1 = {1:2,3:4,6:7,9:10} print dict((v,k) for k,v in dict.items()) 结果 {2:1.4:3,10:9,7:6} res = [{' ...

  8. AlteraFPGA使用通用SPIFlash - 张亚群的技术专栏 - 博客频道 - CSDN.NET

    AlteraFPGA使用通用SPIFlash - 张亚群的技术专栏 - 博客频道 - CSDN.NET Altera器件有EPCS系列配置器件,其实,这些配置器件就是我们平时通用的SPIFlash,据 ...

  9. 使用struts2进行文件下载以及下载权限控制的例子

    本测试有两个模块,一个是文件上上传,一个是文件下载,文件下载的时候会检查是否足有权限,如果没有,就会转发到登录页面,如果有权限,就会直接启动下载程序,给浏览器一个输出流. 下面直接上我的代码: 登录表 ...

  10. return die exit 常用

    die()停止程序运行,输出内容exit是停止程序运行,不输出内容return是返回值die是遇到错误才停止exit是直接停止,并且不运行后续代码,exit()可以显示内容.return就是纯粹的返回 ...