1. 程式人生 > >2882: 工藝(最小表示法)

2882: 工藝(最小表示法)

2882: 工藝

Time Limit: 10 Sec Memory Limit: 128 MB

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

資料規模與約定
對於20%的資料, n <= 1000
對於40%的資料, n <= 10000
對於100%的資料, n <= 300000













解:

這是一個模板題。
最小表示法,但是不能用字尾自動機,字符集太大了。
期望複雜度: O ( n )

記錄兩個指標 i j ,列舉比較長度 k

s[i,i+k] = a[j,j+k]
k++

s[i,i+k] < a[j,j+k]
i=i+k

s[i,i+k] > a[j,j+k]
j=j+k

注意比較的時候要取模。
這樣為什麼是對的呢?
拿第二種情況舉例:
i~i+k-1都不可能是最小的,因為用對應的j和它比,都會比它大。

code:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

int a[300005];
int i,j,k,n;

int main()
{
    scanf("%d",&n);
    for(int w=0;w<n;w++)
      scanf("%d",&a[w]);
    i=0,j=1,k=0;
    while(k<n){
        if(a[(i+k)%n]==a[(j+k)%n]) k++;
        else if(a[(i+k)%n]>a[(j+k)%n]) k=0,i+=k+1;
        else if(a[(i+k)%n]<a[(j+k)%n]) k=0,j+=k+1;
        if(i==j) j++;
        if(i>j) swap(i,j);
        if(j>=n) break; 
    }
    for(int w=0;w<n;w++)
      printf("%d ",a[(i+w)%n]);
}