[BZOJ2882]工艺

2882: 工艺

Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 1085  Solved: 469 [Submit][Status][Discuss]

Description

小敏和小燕是一对好朋友。
他们正在玩一种神奇的游戏,叫Minecraft。
他们现在要做一个由方块构成的长条工艺品。但是方块现在是乱的,而且由于机器的要求,他们只能做到把这个工艺品最左边的方块放到最右边。
他们想,在仅这一个操作下,最漂亮的工艺品能多漂亮。
两个工艺品美观的比较方法是,从头开始比较,如果第i个位置上方块不一样那么谁的瑕疵度小,那么谁就更漂亮,如果一样那么继续比较第i+1个方块。如果全都一样,那么这两个工艺品就一样漂亮。

Input

第一行两个整数n,代表方块的数目。
第二行n个整数,每个整数按从左到右的顺序输出方块瑕疵度的值。

Output

一行n个整数,代表最美观工艺品从左到右瑕疵度的值。

Sample Input


10
10 9 8 7 6 5 4 3 2 1

Sample Output


1 10 9 8 7 6 5 4 3 2

HINT

这题可以通过把串复制一遍接在后面,然后SA做,时间卡着过去的
#include <cstdio>
#include <algorithm>
using namespace std;
inline int readint(){
    int n = 0;
    char ch = getchar();
    while(ch < '0' || ch > '9') ch = getchar();
    while(ch <= '9' && ch >= '0'){
        n = (n << 3) + (n << 1) + ch - '0';
        ch = getchar();
    }
    return n;
}
const int maxn = 300000 + 10;
int n, m;
int s[maxn * 2], num[maxn], ref[maxn];
inline bool cmp(int *arr, int x, int y, int l){
    return arr[x] == arr[y] && arr[x + l] == arr[y + l];
}
int sa[maxn * 2], rank[maxn * 2];
int tax[maxn * 2], tp[maxn * 2];
inline void Rsort(){
    for(int i = 0; i <= m; i++) tax[i] = 0;
    for(int i = 1; i <= n; i++) tax[rank[tp[i]]]++;
    for(int i = 1; i <= m; i++) tax[i] += tax[i - 1];
    for(int i = n; i; i--) sa[tax[rank[tp[i]]]--] = tp[i];
}
void suffix(){
    for(int i = 1; i <= n; i++){
        tp[i] = i;
        rank[i] = s[i];
    }
    Rsort();
    for(int w = 1, p; w < n; w <<= 1, m = p){
        p = 0;
        for(int i = n - w + 1; i <= n; i++) tp[++p] = i;
        for(int i = 1; i <= n; i++) if(sa[i] > w) tp[++p] = sa[i] - w;
        Rsort();
        swap(rank, tp);
        rank[sa[1]] = p = 1;
        for(int i = 2; i <= n; i++)
            rank[sa[i]] = cmp(tp, sa[i - 1], sa[i], w) ? p : ++p;
        if(p == n) return;
    }
}
int main(){
    n = readint();
    for(int i = 1; i <= n; i++)
        num[i] = s[i] = readint();
    sort(num + 1, num + n + 1);
    m = unique(num + 1, num + n + 1) - (num + 1);
    for(int t, i = 1; i <= n; i++){
        t = lower_bound(num + 1, num + m + 1, s[i]) - num;
        ref[t] = s[i];
        s[i] = s[i + n] = t;
    }
    n <<= 1;
    suffix();
    n >>= 1;
    int a;
    for(int i = 1; ; i++){
        if(sa[i] <= n){
            a = sa[i];
            break;
        }
    }
    for(int i = 1; i < n; i++)
        printf("%d ", ref[s[a++]]);
    printf("%d", ref[s[a]]);
    return 0;
}

 

或者SAM也可以做,但由于字符集大小是$O(n)$的,所以时间复杂度为$O(nlogn)$
然后就TLE了
#include <map>
#include <cstdio>
using namespace std;
inline int readint(){
    int n = 0;
    char ch = getchar();
    while(ch < '0' || ch > '9') ch = getchar();
    while(ch <= '9' && ch >= '0'){
        n = (n << 3) + (n << 1) + ch - '0';
        ch = getchar();
    }
    return n;
}
const int maxn = 300000 + 10;
struct State{
    int link, len;
    map<int, int> son;
}st[maxn * 4];
int sam_cnt, last;
void sam_init(){
    sam_cnt = last = 0;
    st[0].len = 0;
    st[0].link = -1;
    st[0].son.clear();
}
inline void sam_extend(int idx){
    int cur = ++sam_cnt;
    st[cur].len = st[last].len + 1;
    st[cur].son.clear();
    int p;
    for(p = last; p != -1 && !st[p].son.count(idx); p = st[p].link) st[p].son[idx] = cur;
    if(p == -1) st[cur].link = 0;
    else{
        int q = st[p].son[idx];
        if(st[p].len + 1 == st[q].link) st[cur].link = q;
        else{
            int clone = ++sam_cnt;
            st[clone].len = st[p].len + 1;
            st[clone].son = st[q].son;
            st[clone].link = st[q].link;
            for(; p != -1 && st[p].son[idx] == q; p = st[p].link) st[p].son[idx] = clone;
            st[cur].link = st[q].link = clone;
        }
    }
    last = cur;
}
int n, num[maxn];
int main(){
    n = readint();
    sam_init();
    for(int i = 1; i <= n; i++)
        sam_extend(num[i] = readint());
    for(int i = 1; i <= n; i++)
        sam_extend(num[i]);
    int p = 0;
    map<int, int>::iterator it;
    for(int i = 1; i < n; i++){
        it = st[p].son.begin();
        printf("%d ", it -> first);
        p = it -> second;
    }
    printf("%d", st[p].son.begin() -> first);
    return 0;
}

 

坠吼的是最小表示法
#include <cstdio>
const int maxn = 300000 + 10;
int n, num[maxn];
int zx(){
    int i = 1, j = 2, k = 0;
    int nxi, nxj, t;
    while(i <= n && j <= n && k <= n){
        nxi = i + k; if(nxi > n) nxi -= n;
        nxj = j + k; if(nxj > n) nxj -= n;
        t = num[nxi] - num[nxj];
        if(t == 0) k++;
        else{
            if(t > 0) i += k + 1;
            else j += k + 1;
            if(i == j) i++;
            k = 0; 
        }
    }
    return i < j ? i : j;
}
int main(){
    scanf("%d", &n);
    for(int i = 1 ; i <= n; i++) scanf("%d", num + i);
    int a = zx();
    for(int i = 1; i < n; i++){
        printf("%d ", num[a++]);
        if(a > n) a -= n;
    }
    printf("%d", num[a]);
    return 0;
}

 

posted @ 2017-10-04 11:24  jzyy  阅读(182)  评论(0编辑  收藏  举报