1. 程式人生 > >spoj New Distinct Substrings

spoj New Distinct Substrings

vjudge原地爆炸...

題意:求一個字串不同的子串的個數

策略:字尾陣列

利用字尾陣列的sa和height兩個功能強大的陣列,我們可以實現上述操作

首先有個很顯然的結論:一個字串的所有子串=它字尾的所有字首

這是很顯然的,因為一個字尾的字首遍歷了所有以該字尾起點為起點的字串的子串,那麼如果我們遍歷所有後綴的,就能找出這個字串的所有子串了

所以對於一個起點為sa[i]的字串,最多能提供的貢獻就是l-sa[i]+1,而再考慮重複字串的個數,也就是這個字尾所有的與其他字尾最長的公共字首,這個字尾的貢獻就是l-sa[i]+1-height[i]

然後累計即可

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
int sa[50005];
int rk[50005];
int height[50005];
int f1[50005];
int f2[50005];
int f3[50005];
int has[50005];
char s[50005];
int l,m=127;
void init()
{
	memset(sa,0,sizeof(sa));
	memset(rk,0,sizeof(rk));
	memset(has,0,sizeof(has));
	memset(f1,0,sizeof(f1));
	memset(f2,0,sizeof(f2));
	memset(f3,0,sizeof(f3));
	memset(height,0,sizeof(height));
	m=127;
}
void turnit()
{
	memcpy(f3,f1,sizeof(f3));
	memcpy(f1,f2,sizeof(f1));
	memcpy(f2,f3,sizeof(f2));
}
void get_sa()
{
	for(int i=1;i<=l;i++)
	{
		f1[i]=s[i];
		has[f1[i]]++;
	}
	for(int i=2;i<=m;i++)
	{
		has[i]+=has[i-1];
	}
	for(int i=l;i>=1;i--)
	{
		sa[has[f1[i]]--]=i;
	}
	for(int k=1;k<=l;k<<=1)
	{
		int tot=0;
		for(int i=l-k+1;i<=l;i++)
		{
			f2[++tot]=i;
		}
		for(int i=1;i<=l;i++)
		{
			if(sa[i]>k)
			{
				f2[++tot]=sa[i]-k;
			}
		}
		for(int i=1;i<=m;i++)
		{
			has[i]=0;
		}
		for(int i=1;i<=l;i++)
		{
			has[f1[i]]++;
		}
		for(int i=2;i<=m;i++)
		{
			has[i]+=has[i-1];			
		}
		for(int i=l;i>=1;i--)
		{
			sa[has[f1[f2[i]]]--]=f2[i];
			f2[i]=0;
		}
		turnit();
		f1[sa[1]]=1;
		tot=1;
		for(int i=2;i<=l;i++)
		{
			if(f2[sa[i]]==f2[sa[i-1]]&&f2[sa[i]+k]==f2[sa[i-1]+k])
			{
				f1[sa[i]]=tot;
			}else
			{
				f1[sa[i]]=++tot;
			}
		}
		if(tot==l)
		{
			break;
		}
		m=tot;
	}
	for(int i=1;i<=l;i++)
	{
		rk[sa[i]]=i;
	}
	int f=0;
	for(int i=1;i<=l;i++)
	{
		if(rk[i]==1)
		{
			continue;
		}
		if(f)
		{
			f--;
		}
		int j=sa[rk[i]-1];
		while(s[i+f]==s[j+f])
		{
			f++;
		}
		height[rk[i]]=f;
	}
}
void solve()
{
	int ss=0;
	for(int i=1;i<=l;i++)
	{
		ss-=l-sa[i]+1-height[i];
	}
	printf("%d\n",ss);
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		init();
		scanf("%s",s+1);
		l=strlen(s+1);
		get_sa();
		solve();
	}
	return 0;
}