ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF1483F

2022-05-26 19:31:28  阅读:136  来源: 互联网

标签:int 复杂度 CF1483F num sa include rk


没有发现 SA 做法于是来发一篇。

我们考虑大串对小串的贡献,从左往右扫,拿当前扫到的点作为左端点,那么最远的能作为子串的右端点才有可能对答案有贡献。

并且我们发现,作为子串的右端点应当是递增的,否则会出现包含关系。

那么一个小串在大串中作为右端点的次数与在大串中出现次数相等时,就对答案有 1 的贡献。

到这里已经可以做出本题了,大概做法就是套路地把所有串拼在一起进行后缀排序,二分出一个串被包含的后缀排名区间进行区间取最大值,然后对每个串进行一个扫,维护一个右端点指针统计贡献即可,空间复杂度 \(O(n)\),时间复杂度 \(O(n\log n)\)。

但是我们发现复杂度还有优化空间,使用 \(SA-IS\) 进行后缀排序,然后桶排后使用并查集求出一个串被包含的后缀排名区间并区间取最大值,然后离线差分出需要的小串在大串中的出现次数,这样的话如果把并查集复杂度视作常数,时间复杂度就被优化到了 \(O(n)\)。

总复杂度是可以做到线性的,尽管毫无实际意义。

代码是第一种做法。感觉比其他做法代码长多了。

Code

#include<vector>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
namespace EMT{
    typedef long long ll;typedef double db;
    #define pf printf
    #define F(i,a,b) for(int i=a;i<=b;i++)
    #define D(i,a,b) for(int i=a;i>=b;i--)
    inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
    inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
    inline int max(int a,int b){return a>b?a:b;}inline int min(int a,int b){return a<b?a:b;}
    inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
    const int N=2e6+10;
    int s[N],_='z',n,beg[N],fa[N],vl[N],vr[N],wl[N],wr[N],len,Len[N],fa2[N],val[N];char ss[N];
    namespace SA{
        int b[N],sa[N],rk[N],height[N],Emilia[N],Arknights[N],n,m,num;
        inline void getsa(){
            int *x=Emilia,*y=Arknights;
            F(i,1,n)b[x[i]=s[i]]++;m=_;
            F(i,1,m)b[i]+=b[i-1];
            D(i,n,1)sa[b[x[i]]--]=i;
            for(int k=1;k<=n;k<<=1){
                num=0;
                F(i,n-k+1,n)y[++num]=i;
                F(i,1,n)if(sa[i]>k)y[++num]=sa[i]-k;
                memset(b,0,sizeof(int)*(m+1));
                F(i,1,n)b[x[i]]++;
                F(i,1,m)b[i]+=b[i-1];
                D(i,n,1)sa[b[x[y[i]]]--]=y[i],y[i]=0;
                std::swap(x,y);
                x[sa[num=1]]=1;
                F(i,2,n)x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
                if(n==num)break;
                m=num;
            }
        }
        inline void getheight(){
            int k=0;
            F(i,1,n)rk[sa[i]]=i;
            F(i,1,n)if(rk[i]>1){
                if(k)k--;int j=sa[rk[i]-1];
                while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
                height[rk[i]]=k;
            }
        }
        inline void init(){
            getsa(),getheight();
            F(i,1,n+1)fa[i]=fa2[i]=vl[i]=vr[i]=i;
        }
    }using SA::rk;using SA::height;
    inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    inline void merge(int x,int y){
        x=find(x),y=find(y);
        vl[y]=min(vl[y],vl[x]),vr[y]=max(vr[y],vr[x]);
        fa[x]=y;
    }
    inline int find2(int x){return fa2[x]==x?x:fa2[x]=find2(fa2[x]);}
    std::vector<int>in[N];
    inline int ask(int x,int y){return std::upper_bound(in[y].begin(),in[y].end(),wr[x])-std::lower_bound(in[y].begin(),in[y].end(),wl[x]);}
    int ans=0;
    inline void solve(int x){
        static int cnt[N];static bool vis[N];
        int now=0;
        F(i,beg[x],beg[x]+Len[x]-1){
            if(!val[rk[i]]||Len[val[rk[i]]]+i-1<=now)continue;
            now=i+Len[val[rk[i]]]-1,cnt[val[rk[i]]]++;
        }now=0;
        F(i,beg[x],beg[x]+Len[x]-1){
            if(!val[rk[i]]||Len[val[rk[i]]]+i-1<=now)continue;
            now=i+Len[val[rk[i]]]-1;
            if(!vis[val[rk[i]]]&&cnt[val[rk[i]]]==ask(val[rk[i]],x))ans++,vis[val[rk[i]]]=1;
        }now=0;
        F(i,beg[x],beg[x]+Len[x]-1){
            if(!val[rk[i]]||Len[val[rk[i]]]+i-1<=now)continue;
            now=i+Len[val[rk[i]]]-1;
            cnt[val[rk[i]]]=vis[val[rk[i]]]=0;
        }
    }
    int Emilia[N],*b;
    inline short main(){
        n=read();int mx=0;
        F(i,1,n){
            scanf("%s",ss+1);
            Len[i]=strlen(ss+1);
            beg[i]=len+1;mx=max(mx,Len[i]);
            F(j,1,Len[i])s[++len]=ss[j];
            s[++len]=++_;
        }SA::n=len;SA::init();
        static int p1[N],p2[N];
        b=Emilia+1;
        F(i,2,len)b[height[i]]++;
        D(i,len,0)b[i]+=b[i+1];
        F(i,2,len)p1[b[height[i]]--]=i;
        memset(b,0,sizeof(int)*(len+1));
        F(i,1,n)b[Len[i]]++;
        D(i,mx,1)b[i]+=b[i+1];
        F(i,1,n)p2[b[Len[i]]--]=i;
        F(i,1,n){
            F(j,beg[i],beg[i]+Len[i]-1)
                in[i].push_back(rk[j]);
            std::sort(in[i].begin(),in[i].end());
        }
        int j=1;
        F(i,1,n){
            const int v=p2[i];
            while(j<len&&height[p1[j]]>=Len[v])merge(p1[j]-1,p1[j]),j++;
            const int fa=find(rk[beg[v]]);
            wl[v]=vl[fa],wr[v]=vr[fa];
            for(int x=find2(vl[fa]);x<rk[beg[v]];x=find2(x)){
                val[x]=v;fa2[find2(x)]=find2(x+1);
            }
            for(int x=find2(rk[beg[v]]+1);x<=vr[fa];x=find2(x)){
                val[x]=v,fa2[find2(x)]=find2(x+1);
            }
        }
        F(i,1,n)solve(i);
        pi(ans);
        return 0;
    }
}
signed main(){return EMT::main();}

标签:int,复杂度,CF1483F,num,sa,include,rk
来源: https://www.cnblogs.com/letitdown/p/16314640.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有