• [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.count(idx); 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;
    }
  • 相关阅读:
    题解——逃离僵尸岛(BFS+最短路+虚拟节点)
    题解——history(离线并查集)
    最短路计数
    【NOI OL #3】优秀子序列
    枚举子集的方法
    【NOI OL #3】魔法值
    【NOI OL #3】水壶
    【HEOI2012】采花
    【JSOI2009】计数问题
    【POI2015】LOG
  • 原文地址:https://www.cnblogs.com/ruoruoruo/p/7625415.html
Copyright © 2020-2023  润新知