Sequence POJ - 3581(后缀数组)

传送门

先贴下代码,还不知道能过不能过,poj崩了

#include <algorithm>
#include <cstring>
#include <cstdio>
#include<iostream>
using namespace std;
const int maxn = 200000 + 100;
int n, k;
int a[maxn];
int rk[maxn], temp[maxn];

bool compare_sa(int i, int j){
    if(rk[i] != rk[j]) return rk[i] < rk[j];
    else {
        int ri = i+k<=n?rk[i+k]:-1;
        int rj = j+k<=n?rk[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;
        rk[i] = a[i];
    }
    for(k=1; k<=n; k<<=1){
        sort(sa, sa+n, compare_sa);
//        cout<<"sa"<<endl;
//        for(int i=0;i<n;i++){
//            cout<<sa[i]<<" ";
//        }
//        cout<<endl;
        temp[sa[0]] = 1;
        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++) rk[i] = temp[i];
//        cout<<"rk"<<endl;
//        for(int i=0;i<n;i++){
//            cout<<rk[i]<<" ";
//        }
//        cout<<endl;
    }
}

int rev_a[maxn], sa[maxn];
int main() {
    scanf("%d", &n);
    for(int i=0; i<n; i++) scanf("%d", &a[i]);
    reverse_copy(a, a+n, rev_a);
//    for(int i=0;i<n;i++){
//        cout<<rev_a[i]<<" ";
//    }
//    cout<<endl;
    construct_sa(rev_a, n, sa);
    int p1;
    for(int i=0; i<n; i++){
        p1 = n - sa[i];
        if(p1>=1 && n-p1>=2) break;
    }
    int m = n-p1;
    reverse_copy(a+p1, a+n, rev_a);
    reverse_copy(a+p1, a+n, rev_a+m);
//    cout<<endl;
//    for(int i=0;i<2*m;i++){
//        cout<<rev_a[i]<<" ";
//    }
//    cout<<endl;
    construct_sa(rev_a, 2*m, sa);
    int p2;
    for(int i=0; i<2*m; i++){
        p2 = p1 + m - sa[i];
        //cout<<m<<" "<<sa[i]<<endl;
        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]);
    return 0;
}
/*
9
8 4 -1 5 0 5 0 2 3
*/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值