HDU 5785 Interesting manacher + 延迟标记
题意:给你一个串,若里面有两个相邻的没有交集的回文串的话,设为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 + 延迟标记的更多相关文章
- HDU5785 Interesting(Manacher + 延迟标记)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5785 Description Alice get a string S. She think ...
- HDU 5785 Interesting
题目: 大概说给一个字符串,找到其所有子串[i...k]满足它是由两个回文串拼成的,求Σi*k. 分析: 用val[1][i]表示以i结尾的回文串的起始位置的和val[0][i]表示以i起始的回文串的 ...
- HDU 4391 Paint The Wall(分块+延迟标记)
Paint The Wall Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- 杭电 HDU ACM 1698 Just a Hook(线段树 区间更新 延迟标记)
欢迎"热爱编程"的高考少年--报考杭州电子科技大学计算机学院 Just a Hook Time Limit: 4000/2000 MS (Java/Others) Memor ...
- HDU 3468:A Simple Problem with Integers(线段树+延迟标记)
A Simple Problem with Integers Case Time Limit: 2000MS Description You have N integers, A1, A2, ... ...
- [HDOJ4578]Transformation(线段树,多延迟标记)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4578 四种操作:查询.加法.乘法.改数.应该是需要维护三个lazy标记,然后就是套路了.查询是区间内所 ...
- FZU 2171(线段树的延迟标记)
题意:容易理解. 分析:时隔很久,再一次写了一道线段树的代码,之前线段树的题也做了不少,包括各种延迟标记,但是在组队分任务之后,我们队的线段树就交给了另外一个队友在搞, 然后我就一直没去碰线段树的题了 ...
- [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,接下 ...
随机推荐
- 第 七 课 go的运算符
http://www.runoob.com/go/go-operators.html 算术运算符 关系运算符 逻辑运算符 位运算符 赋值运算符 其他运算符 返回变量存储地址: & 指针变量: ...
- numpy.matlib.randn(标准正态分布)
#网址 http://docs.scipy.org/doc/numpy/reference/generated/numpy.matlib.randn.html#numpy.matlib.randn n ...
- 十道海量数据处理面试题 - 数据分析与数据挖掘技术-炼数成金-Dataguru专业数据分析社区
1.海量日志数据,提取出某日访问百度次数最多的那个IP. 首先是这一天,并且是访问百度的日志中的IP取出来,逐个写入到一个大文件中.注意到IP是32位的,最多有个2^32个IP.同样可以采用映射的方法 ...
- java数据结构读书笔记--引论
1 递归简论 需求:求出f(x)=2f(x-1)+x²的值.满足f(0)=0 public class Recursion { // 需求: 求出f(x)=2f(x-1)+x²的值.满足f(0)=0 ...
- Hive 进阶
两种情况下不走map-reduce: 1. where ds >' ' //ds 是partition 2. select * from table //后面没有查询条件,什么都没有 1.建表 ...
- mahout过滤推荐结果 Recommender.recommend(long userID, int howMany, IDRescorer rescorer)
Recommender.recommend(uid, RECOMMENDER_NUM, rescorer); Recommender.recommend(long userID, int howMan ...
- Equals 和 == 的区别--转
在比较Equals 和 ==的区别前.我们先来了解下相关的知识 C#数据类型 1.值类型 值类型有: 值类型包括:简单类型.结构类型.枚举类型. byte(1).sbyte(1).short(2).u ...
- .net core 第一个mvc项目目录结构简析
创建项目的命令 首先来认识一下创建项目可使用的各种命令,.NETCore 的命令都以 dotnet 打头,这很好理解,输入 dotnet xxx,就是执行环境变量指向的 C:\Program ...
- SCUT - 337 - 岩殿居蟹 - 线段树 - 树状数组
https://scut.online/p/337 这个东西是个阶梯状的.那么可以考虑存两棵树,一棵树是阶梯的,另一棵树的平的,随便一减就是需要的阶梯. 优化之后貌似速度比树状数组还惊人. #incl ...
- static及静态方法
一.static 1.方法声明中用关键字static修饰的均为类方法或者静态方法,不用static修饰的方法称为实例方法: 2.实例方法可以调用该类中的实例方法或者类方法,类方法只能调用该类的类方法或 ...