「HAOI2018」字串覆盖

「HAOI2018」字串覆盖

题意:

​ 给你两个字符串,长度都为\(N\),以及一个参数\(K\),有\(M\)个询问,每次给你一个\(B\)串的一个子串,问用这个字串去覆盖\(A\)串一段区间的最大收益是多少?(\(N,M\le100000,K\leq10^9\))其中,子串长度在\(51\)\(2000\)的询问个数不会超过\(11000\)个。

题解:

​ 题目的暗示很明显,分类做。

​ 建出\(sam\),维护\(right\)集。

​ 对于询问大于\(50\)的直接暴力跳。

​ 对于询问小于等于\(50\)的倍增跳。

​ 没了。

​ 本来不想写这篇博客,但是,我调这个题调了很久,为什么呢?我这记录一个神秘\(RE\)的地方。

int merge(int x,int y)
{
    if(!x&&!y)return 0;
    int o=++cnt;
    if(!x||!y)return tr[o]=tr[x^y],o;
    tr[o].ls=merge(tr[x].ls,tr[y].ls);
    tr[o].rs=merge(tr[x].rs,tr[y].rs);
    tr[o].siz=tr[tr[o].ls].siz+tr[tr[o].rs].siz;
    return o;
}

​ 改成直接\(return \ x \ xor \ y\),就好了。gdb出来发现并不是爆数组,而是爆栈???有没有大佬可以教一下。

#include<bits/stdc++.h>
#define fo(i,l,r) for(int i=l;i<=r;i++)
#define of(i,l,r) for(int i=l;i>=r;i--)
#define fe(i,u) for(int i=head[u];i;i=e[i].next)
#define el putchar('\n')
#define ta putchar('    ')
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
inline void open(const char *s)
{
    #ifndef ONLINE_JUDGE
    char str[20];
    sprintf(str,"%s.in",s);
    freopen(str,"r",stdin);
    sprintf(str,"%s.out",s);
    freopen(str,"w",stdout);
    #endif
}
inline int rd()
{
    static int x,f;
    x=0;f=1;
    char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    return f>0?x:-x;
}
const int N=100010,B=27;
const int Ha1=998244353;
const int Ha2=1000000007;
int n,K,m,rt[N<<1];
char s1[N],s2[N];
int ps[N],pl[N];
int h1[N],h2[N],bin1[N],bin2[N];
ll ans[N];
map<pii,int>mp;
struct node{int s,t,l,r,L,id;}q[N];
inline bool cmp(node a,node b){return a.L<b.L;}
ll f[20][N],g[20][N],h[20][N];

namespace Seg{
#define lson tr[o].ls,l,mid
#define rson tr[o].rs,mid+1,r
#define qlson lson,L,min(mid,R)
#define qrson rson,max(mid+1,L),R
struct tree{
    int ls,rs,siz;
    tree(){ls=rs=siz=0;}
}tr[N*40];int cnt=0;

void insert(int &o,int l,int r,int x)
{
    tr[++cnt]=tr[o];o=cnt;++tr[o].siz;
    if(l==r)return;int mid=(l+r)>>1;
    if(x<=mid)insert(lson,x);else insert(rson,x);
}
int query(int o,int l,int r,int L,int R)
{if(L>R)return -1;
    if(!tr[o].siz)return -1;
    if(l==r)return l;
    int mid=(l+r)>>1;
    if(l==L&&r==R){
        if(tr[tr[o].ls].siz)return query(qlson);
        return query(qrson);
    }
    int res=-1;
    if(L<=mid)res=query(qlson);
    if(~res)return res;
    if(R>mid)res=query(qrson);
    return res;
}
int merge(int x,int y)
{
    if(!x||!y)return x^y;
    int o=++cnt;
    tr[o].ls=merge(tr[x].ls,tr[y].ls);
    tr[o].rs=merge(tr[x].rs,tr[y].rs);
    tr[o].siz=tr[tr[o].ls].siz+tr[tr[o].rs].siz;
    return o;
}
}

namespace Sam{
int cnt=1,las=1,len[N<<1],fa[20][N<<1],ch[N<<1][26];

inline int insert(int x)
{
    int p=las,np=las=++cnt;len[np]=len[p]+1;
    for(;p&&!ch[p][x];p=fa[0][p])ch[p][x]=np;
    if(!p)return fa[0][np]=1,np;
    int q=ch[p][x];if(len[q]==len[p]+1)return fa[0][np]=q,np;
    int nq=++cnt;len[nq]=len[p]+1;fa[0][nq]=fa[0][q];fa[0][q]=fa[0][np]=nq;
    memcpy(ch[nq],ch[q],104);for(;p&&ch[p][x]==q;p=fa[0][p])ch[p][x]=nq;
    return np;
}
inline void build()
{static int c[N<<1],pos[N<<1];
    fo(i,1,16)fo(j,2,cnt)fa[i][j]=fa[i-1][fa[i-1][j]];
    fo(i,1,cnt)++c[len[i]];
    fo(i,1,cnt)c[i]+=c[i-1];
    of(i,cnt,1)pos[c[len[i]]--]=i;
    of(i,cnt,2){
        int x=pos[i];
        rt[fa[0][x]]=Seg::merge(rt[fa[0][x]],rt[x]);
    }
}
inline void gao()
{
    int o=1,l=0;
    fo(i,1,n){
        if(ch[o][s2[i]-'a'])++l,o=ch[o][s2[i]-'a'];
        else{
            for(;o&&!ch[o][s2[i]-'a'];o=fa[0][o]);
            if(!o)o=1,l=0;else l=len[o]+1,o=ch[o][s2[i]-'a'];
        }
        ps[i]=o;pl[i]=l;
    }
}
inline int jump(int x,int L){of(i,16,0)if(len[fa[i][x]]>=L)x=fa[i][x];return x;}
}

inline void inithsh()
{
    bin1[0]=bin2[0]=1;
    fo(i,1,n)bin1[i]=1ll*B*bin1[i-1]%Ha1,bin2[i]=1ll*B*bin2[i-1]%Ha2;
    fo(i,1,n)h1[i]=(1ll*h1[i-1]*B%Ha1+s1[i]-'a')%Ha1;
    fo(i,1,n)h2[i]=(1ll*h2[i-1]*B%Ha2+s1[i]-'a')%Ha2;
}
inline pii gethsh(int l,int r){return pii((h1[r]-1ll*h1[l-1]*bin1[r-l+1]%Ha1+Ha1)%Ha1,(h2[r]-1ll*h2[l-1]*bin2[r-l+1]%Ha2+Ha2)%Ha2);}

inline void init(int L)
{
    mp.clear();
    fo(i,0,16)f[i][n+1]=n+1;
    of(i,n,L){
        pii hh=gethsh(i-L+1,i);
        if(mp.count(hh))f[0][i]=mp[hh];else f[0][i]=n+1;
        g[0][i]=i;h[0][i]=1;
        fo(j,1,16){
            f[j][i]=f[j-1][f[j-1][i]];
            g[j][i]=g[j-1][i]+g[j-1][f[j-1][i]];
            h[j][i]=h[j-1][i]+h[j-1][f[j-1][i]];
        }
        if(i+L-1<=n)mp[gethsh(i,i+L-1)]=i+L-1;
    }
}
inline ll gao1(int s,int t,int l,int r,int L)
{
    int p=Sam::jump(ps[r],L);
    l=s;r=t;
    int x=Seg::query(rt[p],1,n,l+L-1,r);
    if(!~x)return 0;
    ll hh0=0,hh1=0;
    of(i,16,0)if(f[i][x]<=r)hh1+=g[i][x],hh0+=h[i][x],x=f[i][x];
    hh1+=x;++hh0;return hh0*K-hh1+hh0*(L-1);
}
inline ll gao2(int s,int t,int l,int r,int L)
{
    int p=Sam::jump(ps[r],L);
    l=s;r=t;
    int x=Seg::query(rt[p],1,n,l+L-1,r);
    if(!~x)return 0;
    ll hh1=0,hh0=0;
    while(~x){
        hh1+=x;++hh0;
        x=Seg::query(rt[p],1,n,x+L,r);
    }
    return hh0*K-hh1+hh0*(L-1);
}

int main()
{open("hh");
    n=rd();K=rd();
    scanf("%s",s1+1);scanf("%s",s2+1);
    fo(i,1,n)Seg::insert(rt[Sam::insert(s1[i]-'a')],1,n,i);
    Sam::build();Sam::gao();
    inithsh();
    m=rd();
    fo(i,1,m){
        int s=rd(),t=rd(),l=rd(),r=rd();
        q[i]=node{s,t,l,r,r-l+1,i};
    }
    sort(q+1,q+m+1,cmp);
    int pre=0;
    fo(i,1,m){
        if(pl[q[i].r]<q[i].L||q[i].t-q[i].s+1<q[i].L)continue;
        if(q[i].L<=50){
            if(q[i].L!=pre)init(q[i].L);
            ans[q[i].id]=gao1(q[i].s,q[i].t,q[i].l,q[i].r,q[i].L);
        }
        else ans[q[i].id]=gao2(q[i].s,q[i].t,q[i].l,q[i].r,q[i].L);
        pre=q[i].L;
    }
    fo(i,1,m)printf("%lld\n",ans[i]);
    return 0;
}

时间复杂度:\(O(50Q\log N)\)

转载于:https://www.cnblogs.com/JackyhhJuRuo/p/10559613.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值