HDU 5442 Favorite Donut 后缀数组

题意:

 给你一个甜甜圈,可以正着次也可以反着次求如何按照字典序最大次

后缀数组正反跑一跑就好了

ACcode:

#include <bits/stdc++.h>
#define maxn 20200
using namespace std;
int t1[maxn<<1],t2[maxn<<1],c[maxn<<1];
int r[maxn<<1],sa[maxn<<1],h[maxn<<1],str[maxn<<1];
inline bool cmp(int *r,int a,int b,int l){
    return r[a]==r[b]&&r[a+l]==r[b+l];
}
inline void da(int n,int m){
    n++;
    int *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){
        int p=0;
        for(int i=n-j;i<n;++i)y[p++]=i;
        for(int i=0;i<n;++i)if(sa[i]>=j)y[p++]=sa[i]-j;
        for(int i=0;i<m;++i)c[i]=0;
        for(int i=0;i<n;++i)c[x[y[i]]]++;
        for(int i=1;i<m;++i)c[i]+=c[i-1];
        for(int i=n-1;i>=0;--i)sa[--c[x[y[i]]]]=y[i];
        swap(x,y);
        p=1;
        x[sa[0]]=0;
        for(int 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(int i=0;i<=n;++i)r[sa[i]]=i;
    for(int i=0;i<n;++i){
        if(k)k--;
        int j=sa[r[i]-1];
        while(str[i+k]==str[j+k])k++;
        h[r[i]]=k;
    }
}
char s[maxn],s1[maxn<<1],s2[maxn<<1];
int pos1,pos2,loop,n;
void doit(){
    string  a="",b="";
    for(int i=0;i<n;++i){
        a+=s1[(pos1+i)%n];
        b+=s2[(pos2+i)%n];
    }
    for(int i=2*n;i>1;i--){
            if(sa[i-1]>=n) break;
            if(h[i]>=n) pos2=sa[i-1];//求反向最大最小下标
        }
    pos2=n-1-pos2;
    pos1++,pos2++;
    if(a==b){
        if(pos1>pos2) printf("%d 1\n",pos2);
        else printf("%d 0\n",pos1);
    }
    else if(a>b) printf("%d 0\n",pos1);
    else printf("%d 1\n",pos2);
}
int main(){
    scanf("%d",&loop);
    while(loop--){
        scanf("%d",&n);
        scanf("%s",s);
        for(int i=0;i<n;++i)
            str[i]=str[i+n]=s1[i]=s1[i+n]=s[i];
        str[2*n]=0;
        da(n*2,256);
        pos1=sa[2*n];
        for(int i=n*2-1,k=0;i>=0;--i,++k)
            str[k]=s2[k]=s1[i];
        da(n*2,256);
        pos2=sa[2*n];
        doit();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值