校内模拟赛 休闲字符串

题目:

  给出长度为n的字符串,你需要找到一些不相交的长为k的段,这些段的字典序必须非降。

分析:

  如果k等于1,那么就是一个最长不降子序列问题。长度不是1的话,从对于fi],从$1~i-k$转移即可,然后树状数组优化。

  用SA预处理每段子串的大小。

代码:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
#include<bitset>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 200005;
char s[N];

int t1[N], t2[N], c[N], sa[N], rnk[N], ht[N], w[N];

void getsa(int n) {
    memset(t1, 0, sizeof(t1));
    memset(t2, 0, sizeof(t2));
    int m = 130, i, *x = t1, *y = t2;
    for (i = 0; i <= m; ++i) c[i] = 0;
    for (i = 1; i <= n; ++i) x[i] = s[i], c[x[i]] ++;
    for (i = 1; i <= m; ++i) c[i] += c[i - 1];
    for (i = n; i >= 1; --i) sa[c[x[i]] -- ] = i;
    for (int k = 1; k <= n; k <<= 1) {
        int p = 0;
        for (i = n - k + 1; i <= n; ++i) y[++p] = i; 
        for (i = 1; i <= n; ++i) if (sa[i] > k) y[++p] = sa[i] - k;
        for (i = 0; i <= m; ++i) c[i] = 0;
        for (i = 1; i <= n; ++i) c[x[y[i]]] ++;
        for (i = 1; i <= m; ++i) c[i] += c[i - 1];
        for (i = n; i >= 1; --i) sa[c[x[y[i]]]--] = y[i];
        swap(x, y);
        p = 2;
        x[sa[1]] = 1;
        for (i = 2; i <= n; ++i) 
            x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? p - 1 : p ++;
        if (p > n) break;
        m = p;
    }
    for (int i = 1; i <= n; ++i) rnk[sa[i]] = i;
    int k = 0;
    ht[1] = 0;
    for (int i = 1; i <= n; ++i) {
        if (rnk[i] == 1) continue;
        if (k) k --;
        int j = sa[rnk[i] - 1];
        while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) k ++;
        ht[rnk[i]] = k;
    }
}
struct Bit{
    int mx[N], n;
    void update(int p,int v) {
        for (; p <= n; p += (p & (-p))) mx[p] = max(mx[p], v);
    }
    int query(int p) {
        int ans = 0;
        for (; p; p -= (p & (-p))) ans = max(ans, mx[p]);
        return ans;
    }
}bit; 
int f[N];
void solve() {
    int n = read(), m = read(), now = 0, k = n - m + 1, Ans = 1;
    scanf("%s", s + 1);
    memset(f, 0, sizeof(f));
    getsa(n);
    w[sa[1]] = ++now;
    for (int i = 2; i <= n; ++i) {
        if (ht[i] < m) now ++;
        w[sa[i]] = now;
    }
    bit.n = now; memset(bit.mx, 0, sizeof(bit.mx));
    for (int i = 1; i <= k; ++i) {
        f[i] = bit.query(w[i]) + 1;
        if (i - m + 1 >= 1) bit.update(w[i - m + 1], f[i - m + 1]);
        Ans = max(Ans, f[i]);
    }
    cout << Ans << "\n";
}
int main() {
    for (int T = read(); T --; solve());
    return 0;
}

 

posted @ 2019-03-26 22:04  MJT12044  阅读(134)  评论(0编辑  收藏  举报