208.11.30【SPOJ694/705】New Distinct Substrings(后缀数组)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/84669546

SPOJ694传送门

SPOJ705传送门


解析:

后缀数组水题。

思路:

考虑每个后缀有多少个前缀是没有出现过的。

那么答案显然是 l e n s a i + 1 h t i \sum len-sa_i+1-ht_i


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

cs int N=50004;
namespace SA{
	char s[N];
	int sa[N],rk[N],ht[N],bin[N],len;
	inline void radix_sort(int *cs x,int *cs y,int m,int n);
	inline void init();
	inline void solve();
}

inline void SA::radix_sort(int *cs x,int *cs y,int m,int n){
	memset(bin+1,0,sizeof(int)*m);
	for(int re i=1;i<=n;++i)++bin[x[i]];
	for(int re i=2;i<=m;++i)bin[i]+=bin[i-1];
	for(int re i=n;i;--i)sa[bin[x[y[i]]]--]=y[i];
}

inline void SA::init(){
	int *x=rk,*y=ht;
	for(int re i=1;i<=len;++i)x[i]=s[i],y[i]=i;
	int n=len,m=128;
	radix_sort(x,y,m,n);
	for(int re i=1,cnt=0;cnt<n;i<<=1){
		cnt=0;
		for(int re j=n-i+1;j<=n;++j)y[++cnt]=j;
		for(int re j=1;j<=n;++j)if(sa[j]>i)y[++cnt]=sa[j]-i;
		radix_sort(x,y,m,n);
		swap(x,y);
		x[sa[1]]=cnt=1;
		for(int re j=2;j<=n;++j)x[sa[j]]=((y[sa[j]]==y[sa[j-1]]&&y[sa[j]+i]==y[sa[j-1]+i])?cnt:++cnt);
		m=cnt;
	}
	for(int re i=1;i<=n;++i)rk[sa[i]]=i;
	for(int re i=1,k=0,j;i<=len;ht[rk[i++]]=k)
	for(k?--k:0,j=sa[rk[i]-1];s[i+k]==s[j+k];++k);
}

inline void SA::solve(){
	scanf("%s",s+1);
	len=strlen(s+1);
	s[len+1]='\0';
	init();
	ll ans=0;
	for(int re i=1;i<=len;++i)ans+=len-sa[i]+1-ht[i];
	printf("%lld\n",ans);
}

int T;
signed main(){
	scanf("%d",&T);
	while(T--)SA::solve();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/84669546