JZOJ622220190617可爱

Posted paul-guderian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JZOJ622220190617可爱相关的知识,希望对你有一定的参考价值。

题目

给定一个长度为\(n\)的串,定义两个串匹配当且仅当两个串长度相同并且不同字符至多一个

对于每一个长度为\(m\)的子串输出和它匹配的子串个数

$1 \le n \le 10^5 ?, ?m \le n $ 字符集=4

题解

  • 我不知道字符集为什么等于4..
  • 匹配的条件相当于$lcp+lcs \ge m-1 $
  • 正反建\(SA\),倒着枚举\(lcp\)的值,相当于合并\(suffix\)
  • 要求合法的\(lcs\)大于等于\(m-1-lcp\),每次合并在\(preffix\)上二分贡献答案
  • 用线段树维护答案
  • 实现可以启发式+线段树合并
  • 时间复杂度 \(O(n \ log ^2n)\)
#include<bits/stdc++.h>
#define ll long long 
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define il inline 

using namespace std;

const int N=100010,M=200;
int n,m,bin[17],sum[N*M],add[N*M],ls[N*M],rs[N*M],fa[N],sz[N],cnt,st[N],rt[N],lg[N];
vector<int>vec[N];
char s[N];
ll ans[N];

struct SA
    int sa[N],rk[N],ht[N],f[N][17];
    void init()
        //printf("%s\n",s);
        build_sa();
        //for(int i=0;i<n;++i)printf("% 2d",sa[i]);puts("");
        build_ht();
        //for(int i=0;i<n;++i)printf("% 2d",ht[i]);puts("");
        build_rmq();
    
    void build_sa()
        int m=128;
        static int x[N],y[N],c[N];
        for(int i=0;i<m;++i)c[i]=0;
        for(int i=0;i<n;++i)c[x[i]=s[i]]++;
        for(int i=1;i<m;++i)c[i]+=c[i-1];
        for(int i=n-1;~i;--i)sa[--c[x[i]]]=i;
        for(int k=1,p=0;k<n&&p<n;k<<=1,m=p)
            p=0;for(int j=n-k;j<n;++j)y[p++]=j;
            for(int i=0;i<n;++i)if(sa[i]>=k)y[p++]=sa[i]-k;
            for(int i=0;i<m;++i)c[i]=0;
            for(int i=0;i<n;++i)c[x[i]]++;
            for(int i=1;i<m;++i)c[i]+=c[i-1];
            for(int i=n-1;~i;--i)sa[--c[x[y[i]]]]=y[i];
            p=1;swap(x,y);x[sa[0]]=0;
            for(int i=1;i<n;++i)
                x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;
            
        
    
    void build_ht()
        for(int i=0;i<n;++i)rk[sa[i]]=i;
        for(int i=0,j=0,k=0;i<n-1;ht[rk[i++]]=k)
            j=sa[rk[i]-1];if(k)k--;
            while(s[j+k]==s[i+k])++k;
        
    
    il int min(int x,int y)if(x<y)return x;return y;
    void build_rmq()
        for(int i=1;i<n;++i)f[i][0]=ht[i];
        for(int i=1;i<17;++i)
        for(int j=1;j+bin[i]-1<n;++j)
            f[j][i]=min(f[j][i-1],f[j+bin[i-1]][i-1]);
        
    
    il int ask(int l,int r)
        if(l==r)return n+1;
        int t=lg[r-l];
        return min(f[l+1][t],f[r-bin[t]+1][t]);
    
    void find(int x,int y,int&L,int&R)
        x=rk[x];
        int l=0,r=x;
        while(l<r)
            int mid=(l+r)>>1;
            if(ask(mid,x)>=y)r=mid;
            else l=mid+1;
        L=l;
        l=x,r=n;
        while(l<r)
            int mid=(l+r+1)>>1;
            if(ask(x,mid)>=y)l=mid;
            else r=mid-1;
        R=r;
    
pre,suf;
bool cmp(int a,int b)return suf.ht[a]<suf.ht[b];

void pushdown(int k)
    int l=ls[k],r=rs[k];
    if(l)add[l]+=add[k];
    if(r)add[r]+=add[k];
    add[k]=0;

void ins(int&k,int l,int r,int x)
    sum[k=++cnt]++;
    if(l==r)return;
    int mid=(l+r)>>1;
    if(x<=mid)ins(ls[k],l,mid,x);
    else ins(rs[k],mid+1,r,x);

int modify(int k,int l,int r,int x,int y)
    if(!k)return 0;
    if(l==x&&r==y)add[k]++;return sum[k];
    int mid=(l+r)>>1;
    if(y<=mid)return modify(ls[k],l,mid,x,y);
    else if(x>mid)return modify(rs[k],mid+1,r,x,y);
    else return modify(ls[k],l,mid,x,mid)+modify(rs[k],mid+1,r,mid+1,y);

void getans(int k,int l,int r)
    if(!k)return;
    if(l==r)
        ans[n-m-pre.sa[l]]+=add[k];
        return;
    
    if(add[k])pushdown(k);
    int mid=(l+r)>>1;
    getans(ls[k],l,mid);
    getans(rs[k],mid+1,r);

int merge(int x,int y)
    if(!x||!y)return x+y;
    if(add[x])pushdown(x);
    if(add[y])pushdown(y);
    sum[x]+=sum[y];
    ls[x]=merge(ls[x],ls[y]);
    rs[x]=merge(rs[x],rs[y]);
    return x;


int find(int x)return fa[x]==x?x:fa[x]=find(fa[x]);
void comb(int x,int y,int lim)
    x=find(x),y=find(y);
    if(sz[x]>sz[y])swap(x,y);
    for(int i=0,l,r;i<(int)vec[x].size();++i)
        int t=vec[x][i];vec[y].pb(t);
        if(t>n-m)continue;
        pre.find(n-m-t,lim,l,r);
        ans[t]+=modify(rt[y],0,n,l,r);
    
    rt[y]=merge(rt[x],rt[y]);
    fa[x]=y;sz[y]+=sz[x];


int main()
    freopen("lovely.in","r",stdin);
    freopen("lovely.out","w",stdout);
    scanf("%d%d%s",&n,&m,s);
    for(int i=bin[0]=1;i<17;++i)bin[i]=bin[i-1]<<1;
    for(int i=2;i<=n;++i)lg[i]=lg[i>>1]+1;
    s[n++]='$';suf.init();
    reverse(s,s+n-1);pre.init();
    n--;
    for(int i=0;i<n;++i)
        fa[i]=i;sz[i]=1;vec[i].pb(i);
        if(i>n-m)continue;
        ins(rt[i],0,n,pre.rk[n-m-i]);
    
    for(int i=2;i<=n;++i)st[i]=i;
    sort(st+2,st+n+1,cmp);
    for(int i=m-1,j=n;~i;--i)
        while(j>1&&suf.ht[st[j]]>=i)
            int x=st[j--],y=x-1;
            comb(suf.sa[x],suf.sa[y],m-1-i);
        
    
    getans(rt[find(0)],0,n);
    for(int i=0;i<=n-m;++i)printf("%lld ",ans[i]);
    return 0;

以上是关于JZOJ622220190617可爱的主要内容,如果未能解决你的问题,请参考以下文章

[JZOJ6346]:ZYB和售货机(拓扑+基环内向森林)

洛谷 P1428 小鱼比可爱

洛谷——P1428 小鱼比可爱

SZTUOJ 1019.总之就是不太可爱

P1428 小鱼比可爱

P1428 小鱼比可爱