bzoj 2806: [Ctsc2012]Cheat

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值