POJ3581
题目大意:给你一个长度为n,数组的第一个是最大的,要求你把这个数组拆分为3段,要求将这3段的元素顺序反转,从而得到字典序最小的数组。
思路:后缀数组
题意:给你两个字符串,让你求两个字符串的最长公共子串
后缀数组模板
题目大意:给你一个长度为n,数组的第一个是最大的,要求你把这个数组拆分为3段,要求将这3段的元素顺序反转,从而得到字典序最小的数组。
思路:后缀数组
#include<iostream>//poj2774
#include<cstdio>
#include<algorithm>
using namespace std;
const int Max = 200100;
int n,a[Max],k;
int rev[Max],sa[Max];
int rank[Max],temp[Max];
bool compare_sa(int i,int j)
{
if(rank[i]!=rank[j])
return rank[i]<rank[j];
else
{
int ri=i+k<=n?rank[i+k]:-1;
int rj=j+k<=n?rank[j+k]:-1;
return ri<rj;
}
}
void construct_sa(int *a,int n,int *sa)
{
for(int i=0;i<n;i++)
{
sa[i]=i;
rank[i]=i<n?a[i]:-1;
}
for(k=1;k<=n;k*=2)
{
sort(sa,sa+n+1,compare_sa);
temp[sa[0]]=0;
for(int i=1;i<=n;i++)
temp[sa[i]]=temp[sa[i-1]]+(compare_sa(sa[i-1],sa[i])?1:0);
for(int i=0;i<=n;i++)
rank[i]=temp[i];
}
}
void solve()
{
//将a反转,然后计算其后缀数组
reverse_copy(a,a+n,rev);
construct_sa(rev,n,sa);//计算整数序列的后缀数组
//确定第一段的分割位置
int p1;
for(int i=0;i<n;i++)
{
p1 = n - sa[i];
if(p1>=1&&n-p1>=2)
break;
}
//将p1之后的字符串反转并重复两次,再计算其后缀数组
int m = n - p1;
reverse_copy(a+p1,a+n,rev);
reverse_copy(a+p1,a+n,rev+m);
construct_sa(rev,m*2,sa);
//确定后两段的分割位置
int p2;
for(int i=0;i<=2*m;i++)
{
p2 = p1 + m - sa[i];
if(p2-p1>=1&&n-p2>=1)
break;
}
reverse(a,a+p1);
reverse(a+p1,a+p2);
reverse(a+p2,a+n);
for(int i=0;i<n;i++)
printf("%d\n",a[i]);
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
solve();
}
POJ2774题意:给你两个字符串,让你求两个字符串的最长公共子串
后缀数组模板
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int Max = 200005;
int wa[Max],wb[Max],wsf[Max],wv[Max],sa[Max];
int rank[Max],height[Max],s[Max];
char str1[Max],str2[Max];
int cmp(int *r,int a,int b,int k)
{
return r[a]==r[b]&&r[a+k]==r[b+k];
}
//倍增O(nlogn)
void getsa(int *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
/***********************************/
/*函数的第一步,要对长度为1的字符串进行排序。一般来说,在字符串
的题目中r的最大值不会很大, r 的最大值不会很大,所以这里使用了
基数排序。如果 r 目中,那么把这段代码改成快速排序*/
for(i=0;i<m;i++) wsf[i]=0;
for(i=0;i<n;i++) wsf[x[i]=r[i]]++;
for(i=1;i<m;i++) wsf[i]+=wsf[i-1];
for(i=n-1;i>=0;i--) sa[--wsf[x[i]]]=i;
/***********************************/
for(p=1,j=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=0;i<n;i++) wv[i]=x[y[i]];
for(i=0;i<m;i++) wsf[i]=0;
for(i=0;i<n;i++) wsf[wv[i]]++;
for(i=1;i<m;i++) wsf[i]+=wsf[i-1];
for(i=n-1;i>=0;i--) sa[--wsf[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++;
}
return;
}
void getheight(int *r,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++) rank[sa[i]]=i;
for(i=0;i<n;i++)
{
if(k)
k--;
else
k=0;
j=sa[rank[i]-1];
while(r[i+k]==r[j+k])
k++;
height[rank[i]]=k;
}
}
int main()
{
char str1[Max],str[Max];
while(~scanf("%s",str1))
{
scanf("%s",str2);
int len1=strlen(str1),len2=strlen(str2);
int num=0;
for(int i=0;i<len1;i++)
s[num++]=str1[i]-'a'+1;
s[num++]=28;
for(int i=0;i<len2;i++)
s[num++]=str2[i]-'a'+1;
s[num]=0;
getsa(s,sa,num+1,30);
getheight(s,num);
int ans=0;
for(int i=2;i<num;i++)
{
if(height[i]>ans)
{
if(sa[i-1]>=0 && sa[i-1]<len1 && sa[i]>=len1)
ans = max(ans,height[i]);
if(sa[i]>=0 && sa[i]<len1 && sa[i-1]>=len1)
ans = max(ans,height[i]);
}
}
printf("%d\n",ans);
}
return 0;
}