• luoguP2408不同子串个数


    传送门

    解法一:后缀数组

    可以知道每一个子串都是后缀的前缀,那么对于第(i)小的后缀的贡献就可以表示为n-sa[i]+1
    然而会存在重复的子串,注意height数组的定义,对于sa[i-1]和sa[i],只有height[i]个子串会被重复计算,每次都减掉就好了
    代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    void read(int &x) {
    	char ch; bool ok;
    	for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    	for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
    }
    #define rg register
    const int maxn=1e5+10;long long ans;
    int n,a[maxn],m='z',x[maxn],y[maxn],num,sa[maxn],rk[maxn],h[maxn];char p[maxn];
    int main()
    {
    	read(n);scanf("%s",p+1);
    	for(rg int i=1;i<=n;i++)a[x[i]=p[i]]++;
    	for(rg int i=1;i<=m;i++)a[i]+=a[i-1];
    	for(rg int i=n;i;i--)sa[a[x[i]]--]=i;
    	for(rg int k=1;k<=n;k<<=1,num=0)
    	{
    		for(rg int i=n-k+1;i<=n;i++)y[++num]=i;
    		for(rg int i=1;i<=n;i++)if(sa[i]>k)y[++num]=sa[i]-k;
    		for(rg int i=1;i<=m;i++)a[i]=0;
    		for(rg int i=1;i<=n;i++)a[x[i]]++;
    		for(rg int i=1;i<=m;i++)a[i]+=a[i-1];
    		for(rg int i=n;i;i--)sa[a[x[y[i]]]--]=y[i];
    		for(rg int i=1;i<=n;i++)y[i]=x[i];
    		num=x[sa[1]]=1;
    		for(rg int i=2;i<=n;i++)
    			if(y[sa[i]]!=y[sa[i-1]]||y[sa[i]+k]!=y[sa[i-1]+k])x[sa[i]]=++num;
    			else x[sa[i]]=num;
    		if(num>=n)break;m=num;
    	}
    	for(rg int i=1;i<=n;i++)rk[sa[i]]=i;
    	for(rg int i=1,k=0,j;i<=n;h[rk[i++]]=k)
    		for(k=k?k-1:k,j=sa[rk[i]-1];p[j+k]==p[i+k];k++);
    	for(rg int i=1;i<=n;i++)ans+=n-sa[i]-h[i]+1;printf("%lld
    ",ans);
    }
    

    解法二:后缀自动机

    建出后缀自动机,拓扑排序就行了
    代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    using namespace std;
    void read(int &x){
    	char ch; bool ok;
    	for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    	for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
    }
    #define rg register
    const int maxn=5e6+10;
    int n,tot,las,pre[maxn],nxt[maxn],h[maxn],cnt,in[maxn];
    char a[maxn];
    long long ans,f[maxn];
    struct sam{int len,link,ch[26];}s[maxn];
    void sam_pre(){s[0].len=0,s[0].link=-1;}
    void ins(int x){
    	int cur=++tot,p=las;s[cur].len=s[p].len+1;
    	while(p!=-1&&!s[p].ch[x])s[p].ch[x]=cur,p=s[p].link;
    	if(p==-1)s[cur].link=0;
    	else{
    		int q=s[p].ch[x];
    		if(s[q].len==s[p].len+1)s[cur].link=q;
    		else{
    			int now=++tot;s[now].len=s[p].len+1;
    			s[now].link=s[q].link;
    			memcpy(s[now].ch,s[q].ch,sizeof s[q].ch);
    			while(p!=-1&&s[p].ch[x]==q)s[p].ch[x]=now,p=s[p].link;
    			s[q].link=s[cur].link=now;
    		}
    	}
    	las=cur;
    }
    void add(int x,int y){pre[++cnt]=y,nxt[cnt]=h[x],h[x]=cnt;}
    void top_sort(){
    	queue<int>q;
    	for(rg int i=0;i<=tot;i++)if(!in[i])q.push(i);
    	while(!q.empty()){
    		int x=q.front();q.pop();
    		ans+=f[x];
    		for(rg int i=h[x];i;i=nxt[i]){
    			f[pre[i]]+=f[x];
    			if(!(--in[pre[i]]))q.push(pre[i]);
    		}
    	}
    }
    int main(){
    	read(n),scanf("%s",a+1),sam_pre();
    	for(rg int i=1;i<=n;i++)ins(a[i]-'a');
    	for(rg int i=0;i<=tot;i++)
    		for(rg int j=0;j<26;j++)
    			if(s[i].ch[j])add(i,s[i].ch[j]),in[s[i].ch[j]]++;
    	f[0]=1,top_sort(),printf("%lld
    ",ans-1);
    }
    
  • 相关阅读:
    在Win7 x64环境中将World Wind Java SDK 2.1.0嵌入到Eclipse中的方法
    WW中文地名标注:输出*.wwp和*.wpl文件
    [转]Microsoft Robotics Studio:微软仿真机器人集成开发环境,简称MSRS
    C#中定义类时关于CLSCompliant属性的声明
    Android Studio中使用Java+OpenGL ES创建Android项目
    [转]使用Unity进行3D开发的思路和主要技术优势
    在C++中实现委托事件的方法
    VS2008新建MFC程序时提示:当前页面的脚本发送错误 不是有效的Win32应用程序的解决办法
    [Web 前端] mockjs让前端开发独立于后端
    [Web 前端] 如何构建React+Mobx+Superagent的完整框架
  • 原文地址:https://www.cnblogs.com/lcxer/p/10457475.html
Copyright © 2020-2023  润新知