zoukankan      html  css  js  c++  java
  • 【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;
    }
    
  • 相关阅读:
    LeetCode 1275. 找出井字棋的获胜者 Find Winner on a Tic Tac Toe Game
    LeetCode 307. 区域和检索
    LeetCode 1271 十六进制魔术数字 Hexspeak
    秋实大哥与花 线段树模板
    AcWing 835. Trie字符串统计
    Leetcode 216. 组合总和 III
    Mybatis 示例之 复杂(complex)属性(property)
    Mybatis 示例之 复杂(complex)属性(property)
    Mybatis 高级结果映射 ResultMap Association Collection
    Mybatis 高级结果映射 ResultMap Association Collection
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/11052044.html
Copyright © 2011-2022 走看看