zoukankan      html  css  js  c++  java
  • 「HAOI2018」字串覆盖

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

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

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

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

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

    查询的话复杂度是 (frac{len_1}{len_2} imes 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
    ",ans[i]);
            return 0;
        }
    }
    signed main(){return yspm::main();}
    
  • 相关阅读:
    操作系统__kali(1)基本操作指令,以及常用工具
    Log4net入门(回滚日志文件篇)
    Log4net入门(日志文件篇)
    Log4net入门(控制台篇)
    openwrt控制GPIO
    openwrt DTS介绍
    openwrt bin文件解析
    STM32(三十)蓝牙通信
    openwrt的led configuration
    uci文件生成脚本函数说明
  • 原文地址:https://www.cnblogs.com/yspm/p/14226442.html
Copyright © 2011-2022 走看看