您的位置:首页 > 理论基础 > 计算机网络

hdu-5442(后缀数组,2015网络赛长春赛区)

2015-09-15 15:13 465 查看
题目链接

题意:给一个字符串,可以将其旋转,求旋转后的正或反方向字典序最大,如abca 正方向最大为 caba,反方向最大为cbaa,所以最大为cbaa。对于结果下标越小越好,相同下标优先选正方向。

思路:后缀自动机,对于正向,将串复制为两倍,用后缀数组得出最大后缀位置即可;对于反向,先将串翻转再x2,然后通过后缀数组得出的最大后缀位置为下标最大的字典序最大串,然后通过height数组>=len求出下标最小位置。

#pragma comment(linker,"/STACK:1024000000,1024000000")
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
const int maxn=60010;
int t1[maxn],t2[maxn],c[maxn];
bool cmp(int *r,int a,int b,int l){
    return r[a]==r[b]&&r[a+l]==r[b+l];
}
void da(int str[],int sa[],int rankk[],int height[],int n,int m){
    n++;
    int i,j,p,*x=t1,*y=t2;
    for(int i=0;i<m;i++) c[i]=0;
    for(int i=0;i<n;i++) c[x[i]=str[i]]++;
    for(int i=1;i<m;i++) c[i]+=c[i-1];
    for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
    for(int j=1;j<=n;j<<=1){
        p=0;
        for(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<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]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
        if(p>=n) break;
        m=p;
    }
    int k=0;
    n--;
    for(i=0;i<=n;i++) rankk[sa[i]]=i;
    for(i=0;i<n;i++){
        if(k) k--;
        j=sa[rankk[i]-1];
        while(str[i+k]==str[j+k]) k++;
        height[rankk[i]]=k;
    }
}
int rankk[maxn],height[maxn];
char str[maxn];
int r[maxn],sa[maxn];
int main()
{
    int t,len;
    cin>>t;
    while(t--){
        //rd(len);
        cin>>len;
        scanf("%s",str);
        for(int i=0;i<len;i++) r[i]=str[i]-'a'+1;
        for(int i=0;i<len;i++) r[i+len]=r[i];
        r[len*2]=0;
        da(r,sa,rankk,height,len*2,27);
        string s1="";
        int ans1=sa[len*2];
        for(int i=0;i<len;i++) s1+=r[i+ans1]+'a'-1;//正向最大
        if(ans1==0) {
            printf("%d %d\n",1,0);
            continue;
        }

        for(int i=0,j=len*2-1;i<j;i++,j--){
            int tt=r[i];r[i]=r[j];r[j]=tt;
        }
        r[len*2]=0;
        da(r,sa,rankk,height,len*2,27);
        string s2="";
        int ans2=sa[len*2];
        for(int i=0;i<len;i++) s2+=r[i+ans2]+'a'-1;//反向最大
        for(int i=2*len;i>1;i--){
            if(sa[i-1]>=len) break;
            if(height[i]>=len) ans2=sa[i-1];//求反向最大最小下标
        }
        ans2=len-1-ans2;
       // cout<<ans1<<" "<<ans2<<endl;
       // cout<<s1<<endl;
       // cout<<s2<<endl;
       ans2++;ans1++;
       if(s1==s2){
        if(ans1>ans2) printf("%d %d\n",ans2,1);
        else printf("%d %d\n",ans1,0);
       }
       else if(s1>s2) printf("%d %d\n",ans1,0);
       else printf("%d %d\n",ans2,1);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: