题意:n个字符顺时针围成一圈,按开头不同,总共形成n个长度为n的字符串.
当n个字符串排序后,问这n个字符串最后一位连起来后为? |n|<=1e5.
知道开头位置i,(i+n-1)直接求出其最后字符.
把字符串复制一遍连起来,然后只要知道后缀i的排名即可.(后缀i长度超过n的部分比较无所谓.若比较则说明前n个字符相等.)
逆序:当前小于等于后缀sa2[i]中最大的为:为第一关键字相等的部分中当前第二关键字最大滴
当n个字符串排序后,问这n个字符串最后一位连起来后为? |n|<=1e5.
知道开头位置i,(i+n-1)直接求出其最后字符.
把字符串复制一遍连起来,然后只要知道后缀i的排名即可.(后缀i长度超过n的部分比较无所谓.若比较则说明前n个字符相等.)
后缀数组的排序内容:
计数排序:a[i]排序后在第几位? 求小于等于a[i]的有多少个.字典序比较:倍增,前2^k字符相等 在比较后2^k个字符.
逆序:当前小于等于后缀sa2[i]中最大的为:为第一关键字相等的部分中当前第二关键字最大滴
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> ii;
const int inf=0x3f3f3f3f;
const int N=2e5+20;
char s[N];
int rk[N],sa[N],sa2[N],c[N],n,m;
void Radix_sort()
{
for(int i=0;i<m;i++)
c[i]=0;
for(int i=0;i<n;i++)
c[rk[i]]++;
for(int i=1;i<m;i++)
c[i]+=c[i-1];
for(int i=n-1;i>=0;i--)
sa[--c[rk[sa2[i]]]]=sa2[i];//c[rk[sa2[i]] :小于等于后缀sa2[i]有多少个.
}
void build_sa()
{
m=255;
for(int i=0;i<n;i++)
rk[i]=s[i],sa2[i]=i;
Radix_sort();
for(int k=1;k<=n;k<<=1)
{
int p=0;
for(int i=n-k;i<n;i++)
sa2[p++]=i;
for(int i=0;i<n;i++)
{
if(sa[i]>=k)
sa2[p++]=sa[i]-k;//用后缀sa[i]为后缀sa[i]-k的第二关键字
}
//
Radix_sort();
swap(rk,sa2);//此时sa2作为旧的rk 节省空间wtf*
rk[sa[0]]=0,p=1;
for(int i=1;i<n;i++)
rk[sa[i]]= sa2[sa[i-1]]==sa2[sa[i]] && sa2[sa[i-1]+k]==sa2[sa[i]+k]?p-1:p++;
if(p>=n)
break;
m=p;
}
}
int main()
{
while(scanf("%s",s)!=EOF)
{
n=strlen(s);
for(int i=0;i<n;i++)
s[i+n]=s[i];
s[2*n]='\0';
int len=n;
n*=2;
build_sa();
for(int i=0;i<n;i++)
{
if(sa[i]<len)
printf("%c",s[sa[i]+len-1]);
}
printf("\n");
}
return 0;
}