bzoj 2806: [Ctsc2012]Cheat

来源:互联网 发布:英国留学移民知乎 编辑:程序博客网 时间:2024/04/28 03:14

2806: [Ctsc2012]Cheat

Time Limit: 20 Sec Memory Limit: 256 MB
Submit: 481 Solved: 276
[Submit][Status]

Description

Input

第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库
的行数
接下来M行的01串,表示标准作文库
接下来N行的01串,表示N篇作文

Output

N行,每行一个整数,表示这篇作文的Lo 值。

Sample Input

1 2
10110
000001110
1011001100

Sample Output

4


HINT

输入文件不超过1100000字节


注意:题目有改动,可识别的长度不小于90%即可,而不是大于90%


solution
g[i]表示i能向前匹配多长(后缀自动机妥妥的)
f[i]表示以i结尾能匹配多少个字符
二分答案L
f[i] = max(f[j] + i - j) =max(f[j] - j) + i;(i - g[i] + 1<=j <= i - L + 1)
用单调队列优化


#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<iostream>#include<algorithm>using namespace std;const int maxn = 1100010;struct Tsam{struct sanode{sanode *f, *ch[3]; int l;}pool[maxn * 2], *root, *tail;int tot;void add(int c, int len){sanode *p = tail, *np = &pool[++ tot];np->l = len; tail = np;for (; p && !p->ch[c]; p = p->f) p->ch[c] = np;if (!p) np->f = root;else if (p->ch[c]->l == p->l + 1) np->f = p->ch[c];else{sanode *q = p->ch[c], *r = &pool[++ tot];*r = *q; r->l = p->l + 1;q->f = np->f = r;for (; p && p->ch[c] == q; p = p->f) p->ch[c] = r;}}void clear(){//memset(pool, 0, sizeof(pool)); 去了这句话从1732ms变成了 852ms root = tail = &pool[tot = 1];}void get_f(char *s, int len, int *f){sanode *p = root; for (int i = 1, l = 0; i <= len; f[i ++] = l)if (p->ch[s[i] - '0']) l ++, p = p->ch[s[i] - '0'];else{while (p && !p->ch[s[i] - '0']) p = p->f;if (!p) l = 0;else l = p->l + 1, p = p->ch[s[i] - '0'];}}}sam;int n, m; char ch[maxn];void init(){int k = 0;scanf("%d%d", &n, &k);sam.clear(); int tot = 0;for (int i = 1; i <= k; i ++){scanf("%s", ch + 1); int len = strlen(ch + 1);for (int j = 1; j <= len; j ++) sam.add(ch[j] - '0', ++ tot);sam.add(2, ++ tot);}}int g[maxn], f[maxn], h[maxn];bool check(int l){int tt = 0, ww = -1;for (int i = 1; i <= m; i ++){f[i] = f[i - 1];if (i - l>= 0){while (tt <= ww && f[i - l] - (i - l) >= f[h[ww]] - h[ww]) ww --;h[++ ww] = i - l;}while (tt <= ww && h[tt] < i - g[i]) tt ++;if (tt <= ww) f[i] = max(f[i], f[h[tt]] + i - h[tt]);}return f[m] >= m * 0.9 - (1e-9);}void solve(){sam.get_f(ch, m, g);int tt = 0, ww = m, ans = 0;while (tt <= ww){int mid = (tt + ww) / 2;if (check(mid)) tt = mid + 1, ans = mid;else ww = mid - 1;}printf("%d\n", ans);}void work(){for (int i = 1; i <= n; i ++){scanf("%s", ch + 1); m = strlen(ch + 1);solve();}}int main(){init();work();return 0;}





0 0
原创粉丝点击