题意:给你一个串,若里面有两个相邻的没有交集的回文串的话,设为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. cookie与web Storage

    一.cookie 1. http头与cookie cookie是HTTP Cookie的简称.该标准要求: (1)服务器的HTTP响应头包含 Set-Cookie字段 响应头Eg: HTTP/1.1 ...

  2. 使用svnadmin对VisualSVN进行项目迁移

    使用svnadmin对VisualSVN进行项目迁移 导出1> 启动命令行cmd2> 运行%VISUALSVN_SERVER%\bin\svnadmin dump PATH-TO-REPO ...

  3. lvs+keepalived和haproxy+heartbeat区别

    最近一直在看一些高可用性的负载均衡方案,当然那些f5之类的硬件设备是玩不起也接触不到了.只能看这些for free的开源方案. 目前使用比较多的就是标题中提到的这两者,其实lvs和haproxy都是实 ...

  4. hdu 1074 状态压缩

    http://acm.hdu.edu.cn/showproblem.php?pid=1074 我们可以断定状态的终止态一定是n个数全部选完的情况,那么它的前一个状态是什么呢,一定是剔除任一门课程后的n ...

  5. Webpack 基础使用

    使用webstorm编译: 1.新建一个工程(最基本的工程) 2.在webstorm的控制台,使用命令行     cnpm install webpack  -g  全局安装 3.安装完后,可以使用 ...

  6. linux日常管理-vmstat命令

    系统负载用w查看.是什么原因造成了系统负载.查看系统负载状态 命令:vmstat vmstat就查看一次 vmstat 1 每秒钟更新一次.按ctrl+c取消. vmstat 1 5 每秒钟更新一次, ...

  7. js中一些小知识点总结--持续更新

    以下知识点来自于编写高质量代码-改善JavaScript程序的188个建议,只用于自我知识的补充. 一.NaN 1.NaN是一个特殊的数量值,不表示一个数字,尽管下面的代码仍然是返回类型为number ...

  8. new LayoutParams 使用

    ImageView imageView = new ImageView(mcontext); LayoutParams layoutParams = new LayoutParams(150,130) ...

  9. 3. Shodan新手入坑指南

    什么是 Shodan? 首先,Shodan 是一个搜索引擎,但它与 Google 这种搜索网址的搜索引擎不同,Shodan 是用来搜索网络空间中在线设备的,你可以通过 Shodan 搜索指定的设备,或 ...

  10. hdu1081

    #include<iostream> using namespace std; int GetMaxNum(int a[],int n) //求最大字段和 { int i,sum=0,ma ...