[CTSC 2012]熟悉的文章

二分+单调队列优化dp+后缀自动机

//CTSC2012 熟悉的文章
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e7;
#define ll long long
char s[maxn];
struct node {
    int fa;
    int v;
    int ch[2];
}t[maxn];
int n,m;
int siz = 1;
int rt = 1;
int lst = 1;
inline void extend(int c) {
    int p = lst,np = ++siz;
    t[np].v = t[p].v + 1;
    for(;p && !t[p].ch[c];p = t[p].fa) {
        t[p].ch[c] = np;
    }
    if(!p) {
        t[np].fa = rt;
    }
    else {
        int q = t[p].ch[c];
        if(t[q].v == t[p].v + 1) {
            t[np].fa = q;
        }
        else {
            int nq = ++siz;
            t[nq] = t[q];
            t[nq].v = t[p].v + 1;
            t[q].fa = t[np].fa= nq;
            for(;p && t[p].ch[c] == q;p =t[p].fa) {
                t[p].ch[c] = nq;
            }
        }
    }
    lst = np;
}

int len[maxn];
int f[maxn];

inline void get() {
    int root = rt;
    int res = 0;
    for(int i = 1;i <= n; ++i) {
        int c = s[i] - '0';
        if(t[root].ch[c]) root = t[root].ch[c],res++;
        else {
            while(root && !t[root].ch[c]) {
                root = t[root].fa;
            }
            if(!root) {
                root = rt;
                res = 0;
            }
            else {
                res = t[root].v + 1;
                root = t[root].ch[c];
            }
        }
        len[i] = res;
    }
}

int q[maxn];
int head,tail;
inline bool ok(int mid) {
    head = 1;
    tail = 0;
    for(int i = 1;i <= n; ++i) {
        f[i] = f[i - 1];
        if(i - mid < 0) {
            continue;
        }
        while(head <= tail && f[q[tail]] - q[tail] < f[i - mid] - i + mid) {
            tail --;
        }
        q[++tail] = i - mid;
        while(head <= tail && q[head] < i - len[i]) {
            head ++;
        }
        if(head <= tail) {
            f[i] = max(f[i],f[q[head]] + i - q[head]);
        }
    }
    return f[n] * 10 >= n * 9;
}

inline void binary_srch() {
    get();
    int l = 0,r = n;
    int ans = 0;
    while(l <= r) {
        int mid = (l & r) + ((l ^ r) >> 1);
        if(ok(mid)) {
            ans = mid,l = mid + 1;
        }
        else r = mid - 1;
    }
    printf("%d\n",ans);
}

int main () {
    scanf("%d %d",&m,&n);
    for(int i = 1;i <= n; ++i) {
        scanf("%s",s+1);
        int len = strlen(s + 1);
        lst = rt;
        for(int j = 1;j <= len; ++j) {
            extend(s[j] - '0');
        }
    }
    for(int i = 1;i <= m; ++i) {
        scanf("%s",s+1);
        n = strlen(s+1);
        binary_srch();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/akoasm/p/9494114.html