• P6640 [BJOI2020] 封印 SAM


    题意:

    戳这里

    分析:

    • 暴力:

    对于每一次询问,在t里面哈希找最长总共子串,单次复杂度(O(|t|log |t|)) ,总复杂度 (O(q|t|log |t|)),期望得分:50pts

    • 正解:

    对于最长公共子串问题考虑后缀字符串算法

    我们发现,对于暴力做法单次查询的复杂度过高,所以考虑使用SAM进行优化,我们可以直接求出每一个i,求出最长的 (len[i]) 使得 (s[i-len[i]+1,i]) 为 t 的一个子串,那么我们的答案就是 (max{i-max(l,i-len[i]+1)+1})

    对于第二个 max 我们分类讨论:

    1. (l> i-len[i]+1)(ans=max(i-l+1))
    2. (lle i-len[i]+1)(ans=max(len[i]))

    仔细思考一下我们会发现,(i-len[i]+1) 是单调不减的,感性理解,最长公共子串的左端点只会不断右移

    所以我们可以对于询问按 l 升序排序,然后双指针每次找到分界点 i,查询区间最值就可以了

    tip: 树状数组查询区间最值的时候,需要一部分跳(lowbit),一部分暴力取max

    代码:

    #include<bits/stdc++.h>
    #define inl inline
    #define reg register
    
    using namespace std;
    
    namespace zzc
    {
        inl int read()
        {
            int x=0,f=1;char ch=getchar();
            while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
            while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
            return x*f;
        }
    
        const int maxn = 6e5+5;
        int n,m,qt;
        int length[maxn],ans[maxn];
        char s[maxn],t[maxn];
        struct que
        {
            int l,r,id;
            bool operator <(const que &b)const
            {
                return l<b.l;
            }
        }q[maxn];
    
        struct suffix_automaton
        {
            int tot,lst;
            int len[maxn],trans[maxn][26],link[maxn];
            suffix_automaton(){tot=lst=1;}
    
            inl void insert(int x)
            {
                int cur=++tot,tmp=lst;lst=tot;
                len[cur]=len[tmp]+1;
                for(;tmp&&!trans[tmp][x];tmp=link[tmp]) trans[tmp][x]=cur;
                if(!tmp) link[cur]=1;
                else
                {
                    int q=trans[tmp][x];
                    if(len[tmp]+1==len[q]) link[cur]=q;
                    else
                    {
                        int clone=++tot;
                        len[clone]=len[tmp]+1;
                        link[clone]=link[q];
                        for(reg int i=0;i<=25;i++) trans[clone][i]=trans[q][i];
                        link[cur]=link[q]=clone;
                        for(;tmp&&trans[tmp][x]==q;tmp=link[tmp]) trans[tmp][x]=clone;
                    }
                }
            }
            
            inl void build()
            {
                for(reg int i=1;i<=m;i++) insert(t[i]-'a');
                for(reg int i=1,now=1,tmp=0;i<=n;i++)
                {
                    while(now&&!trans[now][s[i]-'a']) now=link[now],tmp=len[now];
                    if(!now) now=1,tmp=0;
                    else now=trans[now][s[i]-'a'],tmp++;
                    length[i]=min(tmp,i);
                }
            }
        }sam;
        
        struct bit
        {
            int c[maxn];
    		inl int lowbit(int x) {return x&(-x);}
    		inl void add(int x,int k) {for(reg int i=x;i<=n;i+=lowbit(i)) c[i]=max(c[i],k);}
    		inl int query(int l,int r)
    		{
    			int res=0;
    			while(l<=r)
    			{
    				while(r-lowbit(r)>=l) res=max(res,c[r]),r-=lowbit(r);
    				res=max(res,length[r--]);
    			}
    			return res;
    		}
        }tr;
    
        void work()
        {
            scanf("%s",s+1);n=strlen(s+1);
            scanf("%s",t+1);m=strlen(t+1);
            sam.build();
            for(reg int i=1;i<=n;i++) tr.add(i,length[i]);
            qt=read();
            for(reg int i=1;i<=qt;i++) 
            {
                q[i].l=read();q[i].r=read();
                q[i].id=i;
            }
            sort(q+1,q+qt+1);
            for(reg int i=1,j=1,l=1;i<=n&&j<=qt;l++)
            {
                while(i<=n&&i-length[i]+1<l) i++;
                while(j<=qt&&q[j].l==l)
                {
                    if(i-1>=l) ans[q[j].id]=min(i-1,q[j].r)-l+1;
                    if(i<=q[j].r) ans[q[j].id]=max(ans[q[j].id],tr.query(max(i,l),q[j].r));
                    j++;
                }
            }
            for(reg int i=1;i<=qt;i++) printf("%d
    ",ans[i]);
        }
    
    }
    
    int main()
    {
        zzc::work();
        return 0;
    }
    
  • 相关阅读:
    常用正则表达式
    偶得
    监控文件夹里面文件修改的小程序
    使用Windows服务发布WCF服务
    查看wcf服务中方法测试客户端
    twitter注册使用指南
    打包工具使用下载
    c#多线程编程
    请确保此文件可访问并且是一个有效的程序集或COM组件
    添加Service Reference, 无法为服务生成代码错误的解决办法
  • 原文地址:https://www.cnblogs.com/youth518/p/14411522.html
Copyright © 2020-2023  润新知