zoukankan      html  css  js  c++  java
  • 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
    ",ret);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    代码操作
    购物车
    利息计算器
    生成海报
    知识库
    JavaScript处理字符串--参照W3C
    C#输入排序-冒泡
    enum举例
    C# 表达式计算器----数据结构
    C# 测试单词的完美度
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/4621761.html
Copyright © 2011-2022 走看看