您的位置:首页 > 其它

bzoj 2806: [Ctsc2012]Cheat

2014-12-06 10:31 423 查看


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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp 后缀自动机