1. 程式人生 > >最小表示法模板(洛谷P1368 工藝)(最小表示法)

最小表示法模板(洛谷P1368 工藝)(最小表示法)

洛谷題目傳送門

最小表示是指一個字串通過迴圈位移變換(第一個移到最後一個)所能得到的字典序最小的字串。

因為是環狀的,所以肯定要先轉化為序列,把原串倍長。

設決策點為一個表示法的開頭。比較兩個決策點\(i,j\),找到它們的LCP(假設長度為\(k\))。

假設\(s_{i+k}>s_{j+k}\),那麼顯然決策\(s_{i...i+k}\)是分別不優於決策\(s_{j...j+k}\)的,直接跳過這一部分即可。\(s_{i+k}<s_{j+k}\)同理。

時間複雜度\(O(n)\)

#include<bits/stdc++.h>
#define LL long long
#define RG register
#define R RG int
#define G if(++ip==ie)fread(ip=buf,1,SZ,stdin)
using namespace std;
const int SZ=1<<19,N=6e5+9;
int a[N];
char buf[SZ],*ie=buf+SZ,*ip=ie-1;
inline int in(){
    G;while(*ip<'-')G;
    R x=*ip&15;G;
    while(*ip>'-'){x*=10;x+=*ip&15;G;}
    return x;
}
int main(){
    R n=in(),i,j,k;
    for(i=0;i<n;++i)a[i]=a[i+n]=in();
    for(i=j=0;i<n&&j<n;(a[i+k]>a[j+k]?i:j)+=k+1){//跳過無用決策
        if(i==j)++j;//注意特判
        for(k=0;k<n&&a[i+k]==a[j+k];++k);//找LCP
    }
    for(i=min(i,j),j=i+n;i<j;++i)
        printf("%d ",a[i]);
    puts("");
    return 0;
}