题解 P4051 【[JSOI2007]字符加密】
题面
思路:
作为一个后缀数组的初学者,当然首先想到的是后缀数组
把
证明:
神仙一眼就看出这是后缀的裸题,我这个蒟蒻想了半天想不出来
如果我们只对于是就拿了30分
s=bnabn
那么应该这么处理这些缺少的串呢?
我们可以尝试一下把原来的
s=bnabn+bnabn 后缀
bnabnbnabn 在后缀bnbnabn 前面,而实际上bnabn 也同样在bnbna 前面
这样扩展了一倍之后,也就是说题目中变化得到的
答案是不会
比如说:
s=abcd 扩展后
\to s=abcdabcd 对于原串的一种变化结果
bcda 包含在扩展后的
s 中,而bcda 对应的后缀就是bcdabcd ,后缀中多出的bcd 对于bcda 来说,它实际上是bcda 的前缀,也就是说它对bcda 的影响由bcda 决定,这不就是没有影响吗
Code:
#include<bits/stdc++.h>
#define N 1000010
using namespace std;
int n,m,x[N],y[N],c[N],sa[N],p,t;
char s[N];
int main()
{
int i,k;
scanf("%s",s);
t=strlen(s);m=300;n=t<<1;//t是原来s的长度,n是扩展后长度,m初始值实际不用300
for(i=t;i<n;i++) s[i]=s[i-t];
for(i=0;i<n;i++) c[x[i]=s[i]]++;
for(i=1;i<m;i++) c[i]+=c[i-1];
for(i=0;i<n;i++) sa[--c[x[i]]]=i;
for(k=1;k<=n;k<<=1)
{
p=0;
for(i=n-k;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
for(i=0;i<m;i++) c[i]=0;
for(i=0;i<n;i++) c[x[y[i]]]++;
for(i=1;i<m;i++) c[i]+=c[i-1];
for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);p=1;x[sa[0]]=0;
for(i=1;i<n;i++)
x[sa[i]]=(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k])?p-1:p++;
if(p>=n) break;
m=p;
}//都是后缀数组的模板
for(i=0;i<n;i++) if(sa[i]<t) printf("%c",s[(sa[i]+t-1)]);//也就是一个后缀开始的前一位
return 0;
}