zoukankan      html  css  js  c++  java
  • 【BZOJ4698】[SDOI2008] Sandy的卡片(后缀数组+二分)

    点此看题面

    大致题意: 给你(N)个序列,若定义两个相同子串为一个子串内所有数加上一个数后能变成另一个串,求所有序列中的最长相同子串的长度。

    简单的转化

    首先,我们对题目进行一个简单的转化。

    要求子串内所有数加上一个数后能变成另一个串,实际上就是要求这两个子串中相邻元素之差相等。

    因此,我们只要将相邻两元素之差存储下来,就变成求最长公共子串的长度了。

    后缀数组

    要做这道题,我们需要使用后缀数组

    不过此题不需要求(LCP),只要将所有序列拼在一起,中间用一个互不相同的字符隔开,再求出(Height)数组,然后二分即可。

    如何二分

    我们可以二分答案(len)

    考虑如何验证是否存在一个长度大于等于(len)的公共子串。

    其实这个问题等价于:是否存在若干连续的后缀,满足它们的(LCPge len),且它们在(n)个序列中皆有分布

    而这其实在求出(SA)数组和(Height)数组之后直接(O(n))扫一遍就可以了。

    乘上二分(O(logn))的时间复杂度,总复杂度是(O(nlogn))的。

    注意最后答案要加(1)

    代码

    #include<bits/stdc++.h>
    #define N 1000
    #define Len 1500000
    #define Gmax(x,y) (x<(y)&&(x=(y)))
    using namespace std;
    int n,m,len,s[Len+5],p[Len+5];
    class Class_FIO
    {
        private:
            #define Fsize 100000
            #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,Fsize,stdin),A==B)?EOF:*A++)
            #define pc(ch) (void)(putchar(ch))
            int Top,FoutSIze;char ch,*A,*B,Fin[Fsize],Fout[Fsize],Stack[Fsize];
        public:
            Class_FIO() {A=B=Fin;}
            inline void read(int &x) {x=0;while(!isdigit(ch=tc()));while(x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));}
            inline void write(int x) {if(!x) return pc('0');while(x) Stack[++Top]=x%10+48,x/=10;while(Top) pc(Stack[Top--]);}
    }F;
    class Class_SuffixArray//后缀数组
    {
        private:
            int n,Top,vis[N+5],Stack[N+5],SA[Len+5],Height[Len+5],rk[Len+5],pos[Len+5],tot[Len+5];
            inline void RadixSort(int S)
            {
                register int i;
                for(i=0;i<=S;++i) tot[i]=0;
                for(i=1;i<=n;++i) ++tot[rk[i]];
                for(i=1;i<=S;++i) tot[i]+=tot[i-1];
                for(i=n;i;--i) SA[tot[rk[pos[i]]]--]=pos[i];
            }
            inline void GetSA(int *s)
            {
                register int i,k,cnt=0,Size=N<<1;
                for(i=1;i<=n;++i) rk[pos[i]=i]=s[i];
                for(RadixSort(Size),k=1;cnt<n;k<<=1)
                {
                    for(Size=cnt,cnt=0,i=1;i<=k;++i) pos[++cnt]=n-k+i;
                    for(i=1;i<=n;++i) SA[i]>k&&(pos[++cnt]=SA[i]-k);
                    for(RadixSort(Size),i=1;i<=n;++i) pos[i]=rk[i];
                    for(rk[SA[1]]=cnt=1,i=2;i<=n;++i) rk[SA[i]]=(pos[SA[i-1]]^pos[SA[i]]||pos[SA[i-1]+k]^pos[SA[i]+k])?++cnt:cnt;
                }
            }
            inline void GetHeight(int *s)
            {
                register int i,j,k=0;
                for(i=1;i<=n;++i) rk[SA[i]]=i;
                for(i=1;i<=n;++i)
                {
                    if(!(rk[i]^1)) continue;
                    k&&--k,j=SA[rk[i]-1];
                    while(i+k<=n&&j+k<=n&&!(s[i+k]^s[j+k])) ++k;
                    Height[rk[i]]=k;
                }               
            }
        public:
            inline void Init(int len,int *s) {n=len,GetSA(s),GetHeight(s);}
            inline bool Check(int t,int x)//O(n)验证
            {
                register int i;
                while(Top) vis[Stack[Top--]]=0;//清空
                for(i=1;i<=n;++i)
                {
                    if(Height[i]<x) while(Top) vis[Stack[Top--]]=0;//如果Height[i]<x,即LCP(i,i-1)<x,则说明不可行,清空
                    if(!vis[p[SA[i]]]&&(vis[Stack[++Top]=p[SA[i]]]=1)&&!(Top^t)) return true;//如果在n个字符串中皆有分布,就返回true
                }
                return false;//如果找不到,返回false
            }
    }S;
    int main()
    {
        register int i,j,x,y,z,cnt=0,l,r,mid;
        for(F.read(n),i=1;i<=n;++i,s[++len]=N+cnt) for(F.read(x),F.read(y),++cnt,j=1;j<x;++j) F.read(z),s[++len]=z-y,y=z,p[len]=cnt;//读入并存下相邻元素的差值
        for(S.Init(len,s),mid=(l=0)+(r=len)+1>>1;l<r;mid=l+r+1>>1) S.Check(n,mid)?l=mid:r=mid-1;//二分答案
        return F.write(l+1),0;
    }
    
  • 相关阅读:
    Java开源内容管理CMS系统J4CMS支持静态化直接ftp上传到你的空间了
    JAVA数组的定义及用法
    从本地上传整个目录到hdfs的java程序
    图片轮显效果大全
    Windows 自己主动关机命令 shuntdown
    Android源码是这样搞到的(图解)
    JSONObject与JSONArray的使用
    教你用笔记本破解无线路由器password
    tomcat配置文件server.xml具体解释
    SQLite的SQL语法
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ4698.html
Copyright © 2011-2022 走看看