• 【JZOJ6222】【20190617】可爱


    题目

    给定一个长度为(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
    ",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;
    }
    
  • 相关阅读:
    POJ 1251 换成字母编号的最小生成树
    POJ 2421 有一条连通下的最小生成树
    最小生成树-Prim算法和Kruskal算法
    POJ 3083 相对位置的DFS的变形和BFS
    POJ 3278 抓牛简单广搜
    POJ 2488 DFS 模拟 马的跳动
    POJ 1572 字符串替换
    POJ 3984 迷宫问题 BFS+记录路径
    解救人质 BFS模板(迷宫问题)
    解救人质 DFS简单模板
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/11052044.html
Copyright © 2020-2023  润新知