Page 1 of 6123456

SPOJ 744. Longest Permutation

http://www.spoj.com/problems/LPERMUT/

Brief description:

給出一個序列,求最大的 mx,使得存在一個長度為 mx 的連續子序列,使其恰好為 1..mx 的一個排列。

Analysis:

好題。。。Vijos1381 數據太弱,正解應是 O(n) 。

盡量避免使用數據結構。。。我們需要充分利用排列的性質。。。
區間 [l, r] 恰好是 1..len (len = r-l+1)的排列的充分必要條件是:

  • [l, r] 區間的數兩兩不同。
  • s[r]-s[l+1] = 1+2+...+len。。。

為了確保區間中的數字兩兩不同。。。我們設 l[i] 為 i 向左最長可以延伸的距離。。(邊界設 l[0] = 0, l[n+1] = n+1。。)
。。那麼有 l[i] = max(l[i], p[a[i]]+1)。。。(p[a[i]] 是上一個 a[i] 的位置。。。(也可以用 two point 得到這個東西。。。。

void upd(int l, int r, int len){
    if (len < ans) return;
    if (::l[r] <= l && (s[r]-s[l-1])*2 == (1+len)*len) ans = len;
}

。序列被 1 分割成了一些小的區間。。(不能包含兩個相同的 1。。。)。。

____ 1 ____ 1 _________ 1 _____

我們枚舉每個 1.。。討論區間中最大的數字 mx 出現在 1 的左邊還是右邊。。對稱處理。。
。。考慮左邊。。

        for (int j=i-1,mx=1;l[i]<=j;--j){
            checkMax(mx, a[j]);
            upd(j,j+mx-1,mx);
        }

由於 upd() 過程是 O(1) 的。。所以整個演算法是 O(n) 的。。。

//}/* .................................................................................................................................. */

const int N = int(1e5) + 9;

int a[N], s[N], l[N], p[N], n, ans;

void upd(int l, int r, int len){
    if (len < ans) return;
    if (::l[r] <= l && (s[r]-s[l-1])*2 == (1+len)*len) ans = len;
}

int main(){

#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
#endif

    REP_1_C(i, RD(n)) s[i] = s[i-1] + RD(a[i]);

    RST(p); l[0] = 0; REP_1(i, n){
        l[i] = max(l[i-1], p[a[i]]+1); p[a[i]] = i;
        //cout << l[i] << " ";
    }
    l[n+1] = n+1;

    //puts("");

    REP_1(i, n) if (a[i] == 1){

        upd(i, i, 1);

        for (int j=i-1,mx=1;l[i]<=j;--j){
            checkMax(mx, a[j]);
            upd(j,j+mx-1,mx);
        }

        for (int j=i+1,mx=1;l[j]<=i;++j){
            checkMax(mx, a[j]);
            upd(j-mx+1,j,mx);
        }
    }

    OT(ans);
}

SPOJ 7258. Lexicographical Substring Search

http://vjudge.net/problem/viewProblem.action?id=28015

Brief description:

求給定字元串,字典序第 kth 大的子串(重複的算一個)。

Analysis:

演算法一:後綴數組
預處理前 i 個後綴能形成多少個不同的子串,之後二分,複雜度 $O(logn)$。
http://vjudge.net/problem/viewSource.action?id=1577464

演算法二:後綴自動機
DP 出每個狀態出發可以識別多少子串。之後在 SAM 上,逐個字元嘗試。
。。。這種方法時間複雜度較差(依賴於子串長度)、想要通過此題需要常數優化和一定運氣。。。
http://vjudge.net/problem/viewSource.action?id=2604504

Page 1 of 6123456