码迷,mamicode.com
首页 > 其他好文 > 详细

「HAOI2018」字串覆盖

时间:2021-01-06 12:21:04      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:red   就是   ace   include   n+1   order   dig   map   覆盖   

显然的贪心就是尽可能取位置靠前的点

那么问题转化成了维护另一个子串的 \(endpos\) 在这个子串的出现位置

按照古老的套路就是把一个建出来自动机另一个跑匹配

如果 \(l_{ed[r]}<r-l+1\) 那么答案就是 \(0\)

反之考虑当前的点的在 \([tl,tr]\) 中所有的 \(endpos\)

查询的话复杂度是 \(\frac{len_1}{len_2}\times \log_n\)

数据大的时候显然能过,但是数据小的时候会完蛋

那么考虑重新维护一个 \(f_{len,i,j}\) 表示当前字符串是 \(S[i,i+len-1]\) ,后面的 \(2^j\) 的字符串的位置,同时记录 \(sum_{len,i,j}\) 为所有的 \(pos\) 之和

每个询问倍增跳出来所有的位置和求和即可

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define reg register
#define ull unsigned long long
namespace yspm{
    inline int read(){
        int res=0,f=1; char k;
        while(!isdigit(k=getchar())) if(k==‘-‘) f=-1;
        while(isdigit(k)) res=res*10+k-‘0‘,k=getchar();
        return res*f;
    }
    const int N=1e5+10,M=N<<1,SZ=M*40;
    int son[M][26],bz[M][20],len[M],tot=1,las=1,fa[M],sum[SZ],ls[SZ],rs[SZ],num,rt[M],n;
    char s[N],t[N];
    inline void push_up(int x){return sum[x]=sum[ls[x]]+sum[rs[x]],void();}
    inline void upd(int &p,int l,int r,int pos){
        if(!p) p=++num; if(l==r) return sum[p]=1,void();
        int mid=(l+r)>>1; if(pos<=mid) upd(ls[p],l,mid,pos); else upd(rs[p],mid+1,r,pos);
        return push_up(p);
    }
    inline int merge(int x,int y,int l,int r){
        if(!x||!y) return x+y; int p=++num;
        if(l==r) return sum[p]=sum[x]|sum[y],p;
        int mid=(l+r)>>1; ls[p]=merge(ls[x],ls[y],l,mid); rs[p]=merge(rs[x],rs[y],mid+1,r);
        return push_up(p),p;
    }
    inline void extend(int x,int id){
        int tmp=las,np=las=++tot; len[np]=len[tmp]+1; upd(rt[np],1,n,id); 
        while(!son[tmp][x]) son[tmp][x]=np,tmp=fa[tmp];
        if(!tmp) return fa[np]=1,void();
        int q=son[tmp][x]; if(len[q]==len[tmp]+1) return fa[np]=q,void();
        int clone=++tot; len[clone]=len[tmp]+1; for(reg int i=0;i<26;++i) son[clone][i]=son[q][i];
        fa[clone]=fa[q]; fa[q]=fa[np]=clone; while(son[tmp][x]==q) son[tmp][x]=clone,tmp=fa[tmp];
        return ;
    }
    struct edge{int to,nxt;}e[M<<1];
    int head[M],cnt;
    inline void add(int u,int v){
        e[++cnt].to=v; e[cnt].nxt=head[u]; 
        return head[u]=cnt,void();
    }
    inline void dfs(int x){
        for(reg int i=1;i<=19;++i) bz[x][i]=bz[bz[x][i-1]][i-1];
        for(reg int i=head[x];i;i=e[i].nxt){
            bz[e[i].to][0]=x; dfs(e[i].to); 
            rt[x]=merge(rt[x],rt[e[i].to],1,n);
        }return ;
    }
    int ped[N],led[N];
    ll ans[N],k;
    ull hs[N],bas=13331,p[N];
    inline int findpos(int l,int r){
        reg int now=ped[r]; for(reg int i=19;~i;--i) if(len[bz[now][i]]>=r-l+1) now=bz[now][i];
        return now;
    }
    inline int findfir(reg int p,reg int l,reg int r,reg int st,reg int ed){
        if(!p) return -1; if(l==r) return l; 
        reg int mid=(l+r)>>1,res=-1; 
        if(st<=mid) res=findfir(ls[p],l,mid,st,ed); 
        if(res!=-1) return res;
        if(ed>mid) res=findfir(rs[p],mid+1,r,st,ed);
        return res;
    }
    unordered_map<ull,vector<int> > mp;
    inline ull calc(reg int l,reg int r){return hs[r]-hs[l-1]*p[r-l+1];}
    struct node{
        int id,pos,st,ed;
        node(){}    
        node(reg int xx,reg int yy,reg int ww,reg int zz){id=xx; st=yy; ed=ww; pos=zz; return ;}
    };
    struct nd{
        int pos,ct;
        ll sum;
        nd(){}
        nd(reg int xx,reg int yy,reg int zz){pos=xx; sum=yy; ct=zz;}
        nd operator+(const nd &a)const{return nd(a.pos,sum+a.sum,ct+a.ct);}
    }nxt[N][20];
    vector<node> q[60];
    vector<int> tmp;
    signed main(){
        n=read(); k=read(); scanf("%s%s",s+1,t+1);
        for(reg int i=1;i<=n;++i) extend(s[i]-‘a‘,i); 
        for(reg int i=1;i<=tot;++i) add(fa[i],i); dfs(1);
        int now=1,nl=0;
        for(reg int i=1;i<=n;++i){
            if(son[now][t[i]-‘a‘]) now=son[now][t[i]-‘a‘],nl++;
            else{
                while(!son[now][t[i]-‘a‘]&&now) now=fa[now];
                if(!now) now=1,nl=0;
                else nl=len[now]+1,now=son[now][t[i]-‘a‘];   
            } ped[i]=now; led[i]=nl;
        }
        reg int l1,r1,l2,r2,Q=read(); for(reg int i=1;i<=Q;++i){
            l1=read(),r1=read(),l2=read(),r2=read();
            if(led[r2]<r2-l2+1||r1-l1+1<l2-r2+1){ans[i]=0; continue;}
            now=findpos(l2,r2); 
            if(r2-l2+1>50){
                reg ll res=0; reg int p=findfir(rt[now],1,n,l1+(r2-l2+1)-1,r1);
                if(p==-1){ans[i]=0; continue;}
                res+=k-(p-(r2-l2+1)+1); p+=r2-l2+1;
                while(p<=r1&&p!=-1){
                    p=findfir(rt[now],1,n,p,r1);
                    if(p!=-1) res+=k-(p-(r2-l2+1)+1),p+=r2-l2+1; 
                } ans[i]=res;
            }else q[r2-l2+1].push_back(node(i,l1,r1,now));
        } p[0]=1; 
        for(reg int i=1;i<=n;++i) p[i]=p[i-1]*bas,hs[i]=hs[i-1]*bas+s[i];
        for(reg int len=1;len<=50;++len){
            if(!q[len].size()) continue;
            mp.clear(); 
            for(reg int i=len;i<=n;++i){
                ull res=hs[i]-hs[i-len]*p[len];
                nxt[i][0]=(nd){0,i-len+1,1};
                if(mp.count(res)){
                    reg int r=-1;
                    for(reg int j=mp[res].size()-1;~j;--j){
                        if(mp[res][j]<=i-len){r=j;break;} 
                    }
                    while(r>=0) if(nxt[mp[res][r]][0].pos==0) nxt[mp[res][r]][0].pos=i,--r; else break;
                }mp[res].push_back(i); 
            }
            for(reg int i=n;i>=len;--i){
                for(reg int j=1;nxt[nxt[i][j-1].pos][j-1].pos;++j) nxt[i][j]=nxt[i][j-1]+nxt[nxt[i][j-1].pos][j-1];
            } 
            for(auto p:q[len]){
                reg int st=findfir(rt[p.pos],1,n,p.st+len-1,p.ed);
                if(st==-1){ans[p.id]=0;continue;}
                reg ll s=0,c=0; 
                for(reg int i=19;~i;--i){
                    if(nxt[st][i].pos&&nxt[st][i].pos<=p.ed){
                        s+=nxt[st][i].sum,c+=nxt[st][i].ct; 
                        st=nxt[st][i].pos; 
                    }
                } c++; s+=st-len+1;
                ans[p.id]=1ll*k*c-s;
            }
            for(reg int i=len;i<=n;++i) memset(nxt[i],0,sizeof(nxt[i]));
        } 
        for(reg int i=1;i<=Q;++i) printf("%lld\n",ans[i]);
        return 0;
    }
}
signed main(){return yspm::main();}

「HAOI2018」字串覆盖

标签:red   就是   ace   include   n+1   order   dig   map   覆盖   

原文地址:https://www.cnblogs.com/yspm/p/14226442.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!