zoukankan      html  css  js  c++  java
  • 洛谷 SP705 【后缀数组】

    传送门
    回来复习一下后缀数组,感觉之前不理解的地方突然都能理解了 >w<。
    说实话后缀数组比后缀自动机简单。
    这道题要求本质不同的子串数量,可以类比后缀自动机的方法,后缀i贡献的数量就是i的长度-height[rank[i]],因为之前那几个前缀和某一个后缀的前缀重复了。

    #include <bits/stdc++.h>
    using namespace std;
    const int N=1e5+10;
    char s[N];
    int n,m,sa[N*2],rk[N*2],c[N],tp[N*2],ht[N*2],ans;
    
    void getsa(){
    	m='z';
    	//首先将后缀按首字母排序 
    	for(int i=1;i<=m;i++) c[i]=0;
    	for(int i=1;i<=n;i++) c[rk[i]=s[i]]++;
    	for(int i=1;i<=m;i++) c[i]+=c[i-1];
    	for(int i=n;i>=1;i--) sa[c[rk[i]]--]=i;
    	//倍增算法 
    	for(int w=1,p=0;p<n;w<<=1,m=p){
    		p=0; 
    		//先按第二关键字排序
    		//后缀 n-w+1,...,n 第二关键字为0,排最前面。 
    		for(int i=n-w+1;i<=n;i++) tp[++p]=i;
    		//从小到大扫描sa,将剩余的后缀依次排好
    		//如果扫描到一个后缀标号大于w,说明它作为后缀sa[i]-w的第二关键字,所以把sa[i]-w排过来。 
    		for(int i=1;i<=n;i++) if(sa[i]>w) tp[++p]=sa[i]-w;
    		//此时tp数组里存的是以第二关键字排序的结果,然后再以第一关键字基数排序
    		for(int i=1;i<=m;i++) c[i]=0;
    		for(int i=1;i<=n;i++) c[rk[i]]++;
    		for(int i=1;i<=m;i++) c[i]+=c[i-1];
    		for(int i=n;i>=1;i--) sa[c[rk[tp[i]]]--]=tp[i];
    		//然后根据得到的sa数组与上一次的rk数组,来统计本次的rk数组
    		//统计方法就是比较sa中前后两后缀的第一二关键字是否一样
    		swap(tp,rk);
    		rk[sa[1]]=p=1;
    		for(int i=2;i<=n;i++)
    			rk[sa[i]]=(tp[sa[i]]>tp[sa[i-1]]||tp[sa[i]+w]>tp[sa[i-1]+w])?++p:p; 
    	}
    	//根据height数组的性质可以O(n)的求,即 ht[rk[i]]>=ht[rk[i-1]]-1
    	//很好证明,设后缀i-1与k的lcp=len,那么后缀i至少与后缀k+1有lcp=len-1,
    	//因为这两个后缀都是从前面那个后缀上扣了一个字母下去嘛 
    	int k=0;
    	for(int i=1;i<=n;i++){
    		if(rk[i]==1) continue;
    		if(k) k--;
    		int j=sa[rk[i]-1];
    		while(s[i+k]==s[j+k]) k++;
    		ht[rk[i]]=k;
    	}
    	ans=0;
    	for(int i=1;i<=n;i++) ans+=n-i+1-ht[rk[i]];
    	printf("%d
    ",ans);
    }
    
    void solve(){
    	scanf("%s",s+1);
    	n=strlen(s+1);
    	getsa();
    }
    
    int main(){
    	int T;scanf("%d",&T);
    	while(T--) solve();
    	return 0;
    }
    
  • 相关阅读:
    Vue练习三十六:05_01_模拟select控件
    Vue练习三十五:04_09_星级评分系统
    Vue练习三十四:04_07_各种数组方法练习
    Vue练习三十三:04_06_当前输入框高亮显示
    Vue练习三十二:04_05_设置读取属性
    【CC++笔记】指针输出字符串
    【CC++笔记】数组指针越界
    【算法】递归思想
    【学习方法】堕落大学生补救方法
    【数字逻辑】补码技巧
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/12695409.html
Copyright © 2011-2022 走看看