• bzoj 3277: 串


    题目

    这里是一种建广义(SAM)的新姿势,就是每次都把(last)置成(1)

    看起来也没什么科学的地方,但是这就是建广义(SAM)的方法

    之后我们对于那些新插入的位置我们给它涂上颜色

    显然对于一个出现次数超过(k)次的子串,其子树内部必然有超过(k)种颜色

    我们来一遍(hh)的项链就可以统计出来所有节点子树内部的颜色个数了

    之后对于每一个串的每一个前缀我们统计其出现次数超过(k)的后缀

    由于知道这个后缀前缀的结尾,我们直接树上倍增就好了,一直往上跳颜色次数小于(k)的节点,最后再跳一次就是了

    代码

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #define maxn 200005
    #define re register 
    #define LL long long
    #define lowbit(x) ((x)&(-x))
    int lst=1,cnt=1,n,K,num,__;
    struct E{int v,nxt;}e[maxn];
    struct Ask{int x,y,rk;}a[maxn];
    std::vector<int> pos[maxn>>1];
    char S[maxn>>1]; int c[maxn],pre[maxn>>1];
    int fa[maxn],len[maxn],son[maxn][26],t[maxn],sz[maxn],to[maxn];
    int deep[maxn],lg2[maxn],_to[maxn],val[maxn],head[maxn],f[maxn][20];
    inline int cmp(Ask A,Ask B) {return A.y<B.y;}
    inline void add_(int x,int y){e[++num].v=y;e[num].nxt=head[x];head[x]=num;} 
    inline void add(int x,int val){for(re int i=x;i<=cnt;i+=lowbit(i)) c[i]+=val;}
    inline int ask(int x){int now=0;for(re int i=x;i;i-=lowbit(i)) now+=c[i];return now;}
    void dfs(int x) {
    	to[x]=++__,_to[__]=x;sz[x]=1;
    	for(re int i=head[x];i;i=e[i].nxt) deep[e[i].v]=deep[x]+1,dfs(e[i].v),sz[x]+=sz[e[i].v];
    }
    inline void ins(int c,int o)
    {
    	int p=++cnt,f=lst; lst=p;
    	len[p]=len[f]+1,t[p]=o;pos[o].push_back(p);
    	while(f&&!son[f][c]) son[f][c]=p,f=fa[f];
    	if(!f) {fa[p]=1;return;}
    	int x=son[f][c];
    	if(len[f]+1==len[x]) {fa[p]=x;return;}
    	int y=++cnt;
    	len[y]=len[f]+1,fa[y]=fa[x],fa[x]=fa[p]=y;
    	for(re int i=0;i<26;i++) son[y][i]=son[x][i];
    	while(f&&son[f][c]==x) son[f][c]=y,f=fa[f];
    } 
    int main()
    {
    	scanf("%d%d",&n,&K);
    	for(re int i=1;i<=n;i++)
    	{
    		scanf("%s",S+1);
    		int L=strlen(S+1);lst=1;
    		for(re int j=1;j<=L;j++) ins(S[j]-'a',i);
    	}
    	for(re int i=2;i<=cnt;i++) add_(fa[i],i); deep[1]=1,dfs(1);
    	for(re int i=1;i<=cnt;i++) a[i].rk=i,a[i].x=to[i],a[i].y=to[i]+sz[i]-1;
    	std::sort(a+1,a+cnt+1,cmp); int now=1;
    	for(re int i=1;i<=cnt;i++)
    	{
    		if(t[_to[i]])
    		{
    			if(pre[t[_to[i]]]) add(pre[t[_to[i]]],-1);
    			add(i,1),pre[t[_to[i]]]=i;
    		}
    		while(a[now].y==i) val[a[now].rk]=ask(a[now].y)-ask(a[now].x-1),now++;
    	}
    	for(re int i=1;i<=cnt;i++) f[i][0]=fa[i];
    	for(re int i=2;i<=cnt;i++) lg2[i]=lg2[i>>1]+1;
    	for(re int j=1;j<=lg2[cnt];j++)
    		for(re int i=1;i<=cnt;i++) f[i][j]=f[f[i][j-1]][j-1];
    	for(re int i=1;i<=n;i++)
    	{
    		LL ans=0;
    		for(re int j=0;j<pos[i].size();j++)
    		{
    			int T=pos[i][j];
    			for(re int k=lg2[deep[T]];k>=0;k--) 
    				if(val[f[T][k]]<K&&f[T][k]) T=f[T][k];
    			if(val[T]<K) T=fa[T];
    			ans+=len[T];
    		}
    		printf("%lld ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Unity3d for beginners
    iOS 8 swift 键盘不出来 ios 8 uitextfield keyboard not appearing
    关于Cookie跨域的问题
    45种Javascript技巧大全
    新.Net架构必备工具列表
    .NET中的六个重要概念:栈、堆、值类型、引用类型、装箱和拆箱
    ASP.NET 大文件下载的实现思路及代码
    理解 .NET 2015
    转:我是否该放弃VB.Net?
    .net中的一般处理程序实例
  • 原文地址:https://www.cnblogs.com/asuldb/p/10267757.html
Copyright © 2020-2023  润新知