码迷,mamicode.com
首页 > 其他好文 > 详细

P2463 [SDOI2008]Sandy的卡片

时间:2019-02-26 17:35:40      阅读:180      评论:0      收藏:0      [点我收藏+]

标签:怎么   const   span   题目   ace   [1]   长度   子串   turn   

题目链接 \(Click\) \(Here\)

真的好麻烦啊。。事实证明,理解是理解,一定要认认真真把板子打牢,不然调锅的时候真的会很痛苦。。(最好是八分钟能无脑把\(SA\)码对的程度\(QAQ\)

这个题最开始我想的是\(RMQ\)遍历每一个子区间,但是意识到复杂度是\(O(N^2)\)然后就\(GG\)了。怎么说呢,后缀数组和二分似乎是很常见的组合(和莫队也是?),这个题只需要在\(height\)数组里二分\(lcp\)长度即可,\(check\)函数里面处理一下,要让区间内所有原串都有至少一个子串。

#include <bits/stdc++.h>
using namespace std;

const int N = 200010;

int s[N], id[N];
int n, m, num, len, tot = 10000;
int sa[N], tp[N], rk[N], _rk[N], bin[N], height[N];

void get_height (int n) {
    int k = 0;
    for (int i = 1; i <= n; ++i) {
        if (k != 0) k--;
        int j = sa[rk[i] - 1];
        while (s[i + k] == s[j + k]) k++;
        height[rk[i]] = k;
    }
}

void base_sort (int n, int m) {
    for (int i = 0; i <= m; ++i) bin[i] = 0;
    for (int i = 1; i <= n; ++i) bin[rk[tp[i]]]++;
    for (int i = 1; i <= m; ++i) bin[i] += bin[i - 1];
    for (int i = n; i >= 1; --i) sa[bin[rk[tp[i]]]--] = tp[i];
}

void suffix_sort (int n, int m) {
    for (int i = 1; i <= n; ++i) {
        rk[i] = s[i];
        tp[i] = i;
    }
    base_sort (n, m);
    for (int w = 1; w <= n; w <<= 1) {
        int cnt = 0;
        for (int i = n - w + 1; i <= n; ++i) {
            tp[++cnt] = i;
        }
        for (int i = 1; i <= n; ++i) {
            if (sa[i] > w) {
                tp[++cnt] = sa[i] - w;
            }
        }
        base_sort (n, m);
        memcpy (_rk, rk, sizeof (rk));
        rk[sa[1]] = cnt = 1;
        for (int i = 2; i <= n; ++i) {
            rk[sa[i]] = _rk[sa[i]] == _rk[sa[i - 1]] && _rk[sa[i] + w] == _rk[sa[i - 1] + w] ? cnt : ++cnt;
        }
        if (cnt == n) break;
        m = cnt;
    }
}

bool vis[1010]; int sta[N], top = 0;

bool can_use (int l) {
    while (top) vis[sta[top--]] = false;
    for (int i = 1; i <= len; ++i) {
        if (height[i] < l) {
            while (top) vis[sta[top--]] = false;
        }
        if (!vis[id[sa[i]]]) {
            vis[id[sa[i]]] = true;
            sta[++top] = id[sa[i]];
            if (top == n) return true;
        }
    }
    return false;
}

int main () {
    cin >> n;
    int ban = 2000;
    for (int i = 1; i <= n; ++i) {
        cin >> m;
        for (int j = 1; j <= m; ++j) {
            cin >> s[++len]; //把所有的字符串整合到一个里
            id[len] = i; // 表明主权(len号后缀(的lcp)属于串i)
        }
        s[++len] = ++ban; //隔开
    }
    for (int i = len; i >= 1; --i) {
        s[i] = s[i] - s[i - 1] + 4000;
    }
    suffix_sort (len, 10000);
    get_height (len);
    int l = 0, r = len;
    while (l < r) {
        int mid = (l + r + 1) >> 1;
        if (can_use (mid)) {
            l = mid;
        } else {
            r = mid - 1;
        }
    }
    cout << l + 1 << endl;
}

P2463 [SDOI2008]Sandy的卡片

标签:怎么   const   span   题目   ace   [1]   长度   子串   turn   

原文地址:https://www.cnblogs.com/maomao9173/p/10438209.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!