zoukankan      html  css  js  c++  java
  • 6555. 【GDOI2020模拟4.11】黑红兔(brr)(SAM小技♂巧)

    题目描述


    题解

    答案<=√n,所以设f[i][j]表示以i结尾长度为j是否存在,做√n次即可O(n√n)

    可以把选择的串变成长度依次-1,这样当前选择的串长=选择的第几个串

    f[i][j]存在则f[i][j-1]存在,每次删掉当前串末尾字符,若当前串是由上一个串删掉末尾得来的就删掉当前串

    所以把f改成最多的个数,二分判断以[i,i+f[i]-2]或[i+1,i+f[i]-1]为前缀的串是否在[i+f[i],n]中出现,并且对应的f+1>=f[i],大于等于是因为可以通过删减变成f[i]-1

    假设判断是O(log),这样做是log^2

    发现f[i+1]>=f[i]-1,即至少为i删掉一个字符,因此有f[i]<=f[i+1]+1,类似SA一样单调求,总次数为2n

    每次询问[i+f[i],n]的串建出来的SAM的parent树的子树,修改就把整个后缀丢进去

    SAM小技♂巧:

    如何O(log)寻找到一个串的子串对应节点:在parent上倍增,最后一个len>=|S|就是

    还有这道题并不需要考虑一个节点对应的多个串之间的关系,因为丢进去的是整个后缀,是主链上的点上的最长串,因此不需要考虑询问的串在SAM某个节点上的具体大小关系,直接询问即可

    SAM的注意事项(复习):

    ①如果复制节点则要把后面的所有连向该节点的边修改,这样的点在parent树上是连续的一段,手玩一下可得

    ②节点可能小->大,所以倍增要在dfs上预处理

    code

    #include <bits/stdc++.h>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define min(a,b) (a<b?a:b)
    #define max(a,b) (a>b?a:b)
    #define ll long long
    #define file
    using namespace std;
    
    int tr[4000001],a[500001],b[1000001][26],fa[1000001][20],len[1000001],num[1000001];
    int A[1000001][2],ls[1000001],bg[1000001],ed[1000001],f[1000001],n,i,j,k,l,ans,N,Len;
    char st[500001];
    bool bz;
    
    void New(int t,int x) {++N;memcpy(b[N],b[b[t][x]],sizeof(b[N]));b[t][x]=N;fa[N][0]=t;len[N]=len[t]+1;}
    void tNew(int x,int y) {++Len;A[Len][0]=y;A[Len][1]=ls[x];ls[x]=Len;}
    void work(int t)
    {
    	int i;
    	fo(i,1,19) fa[t][i]=fa[fa[t][i-1]][i-1];
    }
    void sam()
    {
    	int i,j,k,l,ls;
    	
    	N=ls=1;
    	fo(i,1,n)
    	{
    		j=fa[ls][0];New(ls,a[i]);ls=N;num[i]=ls;
    		while (j && !b[j][a[i]])
    		{
    			b[j][a[i]]=ls;
    			j=fa[j][0];
    		}
    		if (!j) fa[ls][0]=1;
    		else
    		{
    			if (len[j]+1==len[b[j][a[i]]]) fa[ls][0]=b[j][a[i]];
    			else
    			{
    				k=b[j][a[i]],New(j,a[i]);fa[N][0]=fa[k][0],fa[k][0]=fa[ls][0]=N;
    				j=fa[j][0];
    				while (b[j][a[i]]==k) b[j][a[i]]=N,j=fa[j][0];
    			}
    		}
    	}
    	fo(i,2,N) tNew(fa[i][0],i);
    }
    
    int jump(int t,int x)
    {
    	int i;
    	fd(i,19,0) if (len[fa[t][i]]>=x) t=fa[t][i];
    	return t;
    }
    
    void dfs(int Fa,int t)
    {
    	int i;
    	work(t);
    	
    	bg[t]=++j;
    	for (i=ls[t]; i; i=A[i][1]) if (A[i][0]!=Fa) dfs(t,A[i][0]);
    	ed[t]=j;
    }
    
    void change(int t,int l,int r,int x,int s)
    {
    	int mid=(l+r)/2;
    	
    	tr[t]=max(tr[t],s);
    	if (l==r) return;
    	
    	if (x<=mid) change(t*2,l,mid,x,s);
    	else
    	change(t*2+1,mid+1,r,x,s);
    }
    int find(int t,int l,int r,int x,int y)
    {
    	int s,ans=0,mid=(l+r)/2;
    	
    	if (x<=l && r<=y) return tr[t];
    	
    	if (x<=mid) s=find(t*2,l,mid,x,y),ans=max(ans,s);
    	if (mid<y) s=find(t*2+1,mid+1,r,x,y),ans=max(ans,s);
    	
    	return ans;
    }
    
    bool pd(int x,int y)
    {
    	int i=jump(num[y],y-x+1);
    	return find(1,1,N,bg[i],ed[i])>=y-x+1;
    }
    
    int main()
    {
    	freopen("brr.in","r",stdin);
    	#ifdef file
    	freopen("brr.out","w",stdout);
    	#endif
    	
    	scanf("%s",st);n=strlen(st);
    	fo(i,1,n) a[n-i+1]=st[i-1]-'a',bz=(a[n-i+1]==a[n])?bz:1;
    	if (!bz)
    	{
    		while (n>ans) ++ans,n-=ans;
    		printf("%d
    ",ans);
    		return 0;
    	}
    	
    	sam();
    	j=0;dfs(0,1);
    	
    	fo(i,1,n)
    	{
    		f[i]=f[i-1]+1;
    		while (f[i]>1 && !pd(i-f[i]+1,i-1) && !pd(i-f[i]+2,i)) change(1,1,N,bg[num[i-f[i]+1]],f[i-f[i]+1]),--f[i];
    		
    		ans=max(ans,f[i]);
    	}
    	
    	printf("%d
    ",ans);
    	
    	fclose(stdin);
    	fclose(stdout);
    	
    	return 0;
    }
    
  • 相关阅读:
    out/host/linuxx86/obj/EXECUTABLES/aapt_intermediates/aapt 64 32 操作系统
    linux 查看路由器 电脑主机 端口号 占用
    linux proc进程 pid stat statm status id 目录 解析 内存使用
    linux vim 设置大全详解
    ubuntu subclipse svn no libsvnjavahl1 in java.library.path no svnjavahl1 in java.library.path no s
    win7 安装 ubuntu 双系统 详解 easybcd 工具 不能进入 ubuntu 界面
    Atitit.json xml 序列化循环引用解决方案json
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    Atitit.跨语言  文件夹与文件的io操作集合  草案
    Atitit.atijson 类库的新特性设计与实现 v3 q31
  • 原文地址:https://www.cnblogs.com/gmh77/p/12692024.html
Copyright © 2011-2022 走看看