COJ975 WZJ的数据结构(负二十五)

试题描述

输入一个字符串S,回答Q次问题,给你l,r,输出子序列[l,r]的最长连续回文串长度。

输入

第一行为一个字符串S。

第二行为一个正整数Q。

接下来Q行每行为l,r。

输出

对于每个询问,输出答案。

输入示例

aababababaabababaaa

4

1 3

2 6

1 10

2 7

输出示例

2

5

9

5

其他说明

1<=|S|,Q<=100000

1<=l<=r<=|S|

由于求区间的最长回文串长度,这显然不是很容易的事情,我们考虑用分块来维护答案。

我们每SIZE个元素分成一块,询问时要得到大块之间的答案以及小部分贡献的答案。

前者我们可以预处理出来(马拉车或PAM),时间复杂度O(N^2/SIZE)。

后者我们可以用PAM,当回文串的一段在小段时,肯定是左端在左小段,右端在右小段。两者是对称的,我们开始考虑怎么求回文串右端在右小段的答案。

预处理每个位置在PAM上的节点,但这可能超过询问边界,所以我们要不停地沿失配边向上走,当节点的的长度<=限制长度时返回。

如果暴力的话虽然对于随机数据表现很好,但会被特殊数据卡。因此我们可以用倍增来做,那么这一部分的时间复杂度为O(Q*SIZE*logSIZE)。

总时间复杂度为O(N^2/SIZE+Q*SIZE*logSIZE),实测SIZE取[150,200]即可。

#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<stack>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘;
    return x*f;
}
const int maxn=100010;
char ch[maxn];
int lpos[maxn],rpos[maxn],nowret;
struct PAM {
    int last,cnt,to[maxn][26],l[maxn],fa[maxn];
    int first[maxn],next[maxn],To[maxn],anc[maxn][20],e;
    void init() {
        memset(to,0,sizeof(to));
        memset(l,0,sizeof(l));
        memset(fa,0,sizeof(fa));
        memset(first,0,sizeof(first));
        cnt=fa[0]=1;l[1]=-1;last=e=0;
    }
    void extend(int c,int n,int id) {
        int p=last;
        while(ch[n]!=ch[n-l[p]-1]) p=fa[p];
        if(!to[p][c]) {
            int np=++cnt,k=fa[p];l[np]=l[p]+2;
            while(ch[n]!=ch[n-l[k]-1]) k=fa[k];
            fa[np]=to[k][c];to[p][c]=np;
        }
        nowret=max(nowret,l[last=to[p][c]]);
        if(id>0) lpos[id]=last;
        else rpos[-id]=last;
    }
    stack<int> S;
    void dfs(int x) {
        S.push(x);
        while(!S.empty()) {
            x=S.top();S.pop();
            anc[x][0]=fa[x];
            rep(i,1,19) anc[x][i]=anc[anc[x][i-1]][i-1];
            ren S.push(To[i]);
        }
    }
    void AddEdge(int u,int v) {
        To[++e]=v;next[e]=first[u];first[u]=e;
    }
    void build() {
        fa[1]=1;rep(i,0,cnt) if(i!=1) AddEdge(fa[i],i);
        dfs(1);
    }
    int solve(int x,int limit) {
        if(l[x]<=limit) return l[x];
        for(int i=19;i>=0;i--) if(l[anc[x][i]]>limit) x=anc[x][i];
        return l[fa[x]];
    }
}sol1,sol2;
int n,SIZE;
int ans[750][750],bl[maxn],st[maxn],en[maxn];
int main() {
    scanf("%s",ch+1);n=strlen(ch+1);SIZE=150;
    rep(i,1,n) {
        bl[i]=(i-1)/SIZE+1;
        en[bl[i]]=i;
        if(!st[bl[i]]) st[bl[i]]=i;
    }
    rep(i,1,bl[n]) {
        sol1.init();nowret=0;
        char c=ch[st[i]-1];ch[st[i]-1]=‘~‘;
        rep(j,st[i],n) {
            sol1.extend(ch[j]-‘a‘,j,1);
            ans[i][bl[j]]=max(ans[i][bl[j]],nowret);
        }
        ch[st[i]-1]=c;
    }
    sol1.init();sol2.init();
    rep(i,1,n) sol1.extend(ch[i]-‘a‘,i,i);
    reverse(ch+1,ch+n+1);
    rep(i,1,n) sol2.extend(ch[i]-‘a‘,i,-(n-i+1));
    sol1.build();sol2.build();
    int m=read();
    while(m--) {
        int l=read(),r=read(),ret=0;
        if(bl[l]+1>=bl[r]) rep(i,l,r) ret=max(ret,sol1.solve(lpos[i],i-l+1));
        else {
            ret=ans[bl[l]+1][bl[r]-1];
            rep(i,l,en[bl[l]]) ret=max(ret,sol2.solve(rpos[i],r-i+1));
            rep(i,st[bl[r]],r) ret=max(ret,sol1.solve(lpos[i],i-l+1));
        }
        printf("%d\n",ret);
    }
    return 0;
}

时间: 2024-11-05 15:54:55

COJ975 WZJ的数据结构(负二十五)的相关文章

QT开发(二十五)——QT模板库

QT开发(二十五)--QT模板库 一.QTL模板库简介 QT模板库(QT Template Library 简称QTL)是一套提供对象容器的模板. QTL提供了对象的链表.对象的矢量(动态数组).从一个类型到另一个类型的映射(或称为字典)和相关的迭代器和算法.容器是包含和管理其它对象的一个对象,并且提供迭代器对被包含的对象进行访问. 1.QT容器类简介 容器是能够在内存中存储其他特定类型的对象的对象,一般是通用的模板类.QT提供了自己的一套容器类,即在QT的应用程序中,可以使用标准C++的STL

15、蛤蟆的数据结构笔记之十五栈的应用之栈与递归之八皇后问题

15.蛤蟆的数据结构笔记之十五栈的应用之栈与递归之八皇后问题 本篇名言:"人的一生应当这样度过:当回忆往事的时候,他不致于因为虚度年华而痛悔,也不致于因为过去的碌碌无为而羞愧:在临死的时候,他能够说:"我的整个生命和全部精力,都已经献给世界上最壮丽的事业--为人类的解放而斗争." 继续递归问题,本次是经典的八皇后问题: 欢迎转载,转载请标明出处: 1.  八皇后问题 八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出

攻城狮在路上(叁)Linux(二十五)--- linux内存交换空间(swap)的构建

swap的功能是应付物理内存不足的状况,用硬盘来暂时放置内存中的信息. 对于一般主机,物理内存都差不多够用,所以也就不会用到swap,但是对于服务器而言,当遇到大量网络请求时或许就会用到. 当swap被使用的时候,主机的硬盘灯就会闪烁不停. 本篇介绍两种方式:1.设置一个swap分区   2.创建一个虚拟内存的文件. 一.使用物理分区构建swap: 1.首先是分区: A.fdisk /dev/sda; <== 根据后续提示创建一个分区. B.修改分区的ID,因为fdisk默认将分区的ID作为文件

每日算法之二十五:Divide Two Integers

Divide two integers without using multiplication, division and mod operator. 不使用乘法.除法和求模运算求两个数相除. class Solution { public: long long internalDivide(unsigned long long dividend,unsigned long long divisor) { if(dividend<divisor) return 0; int result =

关于心理的二十五种倾向(查理&amp;#183;芒格)-2

5)避免不一致倾向避免不一致倾向实际上就是人天生就害怕改变.相同是由于人类大脑的生理机制决定的.由于这样的倾向能够带来节省运算空间和能量的优点.这样的抗改变模式的形成,可能的原因例如以下:A) 迅速作出决定对生存来说至关重要,而这样的抗改变模式有助于更快的作出决定;     这里有第四个倾向的因素,对于生存至关重要的反应(遇到生存威胁时),反应一定要快,必须形成固化的模式.这也是我们对于紧急事件的处理常常採用不断反复模拟训练的原因.B) 能够通过群体协作来获得生存优势,假设每一个人总是不停地改变

【管理心得之二十五】组织中的骂名 ----------墙头草

场景再现 ====================== {会议前} 老张:喂,老王.这次的讨论议题你怎么看? 老王:暂时还没有想好,你有什么高见? 老张:这还不简单,以前类似的事发生过. "首先..........其次..........最后........."   你看看怎样? 老王:嗯{点点头} {会议中} 老  张:"方案A 是... ... ... ... " 方案B:"方案B 是... ... ... ... " 方案C:"方

企业搜索引擎开发之连接器connector(二十五)

下面开始具体分析连接器是怎么与连接器实例交互的,这里主要是分析连接器怎么从连接器实例获取数据的(前面文章有涉及基于http协议与连接器的xml格式的交互,连接器对连接器实例的设置都是通过配置文件操作的,具体文件操作尚未详细分析(com.google.enterprise.connector.persist.FileStore类)) 本文以数据库连接器实例为例来分析,数据库类型连接器是通过调用mybatis(sqlmap框架)组件与数据库进行操作的,我们通过前端提交的数据库连接器实例表单信息最终存

二十五、防止表单重复提交

二十五.防止表单重复提交 防止表单重复提交: 有两种方式: 利用重定向<result type = "redirect"/> 使用拦截器 编写jsp页面 <s:form action="regist"> ????????<s:textfield name="name" label="姓名"></s:textfield> ????????<s:token/> ?????

二十五六岁的姑娘

随着时间的推移,我在慢慢的长高,长大,随之而来的责任也越来越重.如果把一个人的一生当做一天来看,那么无疑我已经走过一开始黎明,和初升朝阳的时期了……哪些一切美好希望的寄托已经不再属于我这个年纪该有的了.唯一能做的就是面对现实,到了该吃饭的时间我饿了就是饿了,要吃饭!我感觉我就是处于那个该吃饭时间. 二十五六岁的姑娘应该要有自己的一技之长了,虽然说一切只要想学都还来得及,可是时间不会给你太多准备和努力,只要一眨眼你错过了,那么也许是一辈子的遗憾又或者是那种一切太迟的吃力和无奈! 二十五六岁的姑娘要