2020 牛客多校训练第一场之 A——B-Suffix Array 题解

2020 牛客多校训练第一场之 A——B-Suffix Array 题解_第1张图片
输出描述:
For each test case, print n integers which denote the result.

输入
2
aa
3
aba
5
abaab

输出
2 1
3 2 1
5 4 2 1 3
2020 牛客多校训练第一场之 A——B-Suffix Array 题解_第2张图片

题解:
c[i]的值是i后面离“i指针”对应的字母最近的与s[i]同字符的距离,字符串的后缀数组就与这个c数组的后缀数组。可以把这个c数组给模拟出来,求出它的后缀(当一个字母后面没有和他相同的字母时,无穷大了,就设为数组长度n,最后一位没啥用,随便设一个比较大的数。避免冲突,就设成n+1)。
根据关系求出1个sa数组,把这个字符串翻转过来,去掉第一位就能模拟出结果了。

下面举个例子:
设ab字符串为abaab,它的c数组为231556,列出c的后缀为: 231556,31556,1556,556,56,6。可以求得 sa:312456,反过来去掉首位的6,54213就是答案了。

#include 
using namespace std;
string s;
int n,k,i;
int ran[100010],tmp[100010],sa[100010],c[100010];

bool cmp(int i,int j) // 根据题意搞出这个cmp函数 
{
	if(ran[i]!=ran[j])  return ran[i]<ran[j];
	else
	{
		int ri,rj;
		
		if(i+k<=n)	ri=ran[i+k];
		else	ri=-1;
		
		if(j+k<=n)	rj=ran[j+k];
		else	rj=-1;
		
		return ri<rj;
	}
}

void get_sahh(int sa[]) //求sa数组的函数 
{
	for(i=0; i<=n; i++) {
		sa[i]=i;
		if(i<n)	ran[i]=c[i];
		else	ran[i]=-1;
	}
	
	for(k=1; k<=n; k*=2) {
		sort(sa,sa+n+1,cmp);
		tmp[sa[0]]=0;
		
		for(int i=1; i<=n; i++)
			tmp[sa[i]]=tmp[sa[i-1]]+(cmp(sa[i-1],sa[i]) ? 1 : 0);
		
		for(int i=0; i<=n; i++)	ran[i]=tmp[i];
		
	}
}

int main()
{
	while(~scanf("%d",&n))
	{
		cin>>s;
		int a=n,b=n;
		for(i=n-1; i>=0; i--)
		{
			if(s[i]=='a') {
				if(a==n)  c[i]=(n-a) %n;
				else  c[i]=(n-a+i) %n;
				a=i;
			}
			else {
				if(b==n)  c[i]=(n-b) %n;
				else  c[i]=(n-b+i) %n;
				b=i;
			}
		}
		get_sahh(sa);
		for(i=1; i<=n; i++)	 cout<<sa[i]+1<<" ";
		cout<<endl;
	}
    return 0;
}

你可能感兴趣的:(后缀数组,结论题,题解,字符串)