# 【bzoj2806】[Ctsc2012]Cheat 广义后缀自动机+二分+单调队列优化dp

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

1 2
10110
000001110
1011001100

4

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1100010
using namespace std;
int next[N << 1][2] , fa[N << 1] , dis[N << 1] , last , tot = 1 , n , mx[N] , f[N] , q[N];
char str[N];
void ins(int c)
{
int p = last , np = last = ++tot;
dis[np] = dis[p] + 1;
while(p && !next[p][c]) next[p][c] = np , p = fa[p];
if(!p) fa[np] = 1;
else
{
int q = next[p][c];
if(dis[q] == dis[p] + 1) fa[np] = q;
else
{
int nq = ++tot;
memcpy(next[nq] , next[q] , sizeof(next[q])) , dis[nq] = dis[p] + 1 , fa[nq] = fa[q] , fa[np] = fa[q] = nq;
while(p && next[p][c] == q) next[p][c] = nq , p = fa[p];
}
}
}
bool judge(int mid)
{
int i , l = 1 , r = 0;
for(i = 1 ; i <= n ; i ++ ) f[i] = 0;
for(i = mid ; i <= n ; i ++ )
{
f[i] = f[i - 1];
while(l <= r && f[q[r]] - q[r] < f[i - mid] - i + mid) r -- ;
q[++r] = i - mid;
while(l <= r && q[l] < i - mx[i]) l ++ ;
if(l <= r) f[i] = max(f[i] , f[q[l]] - q[l] + i);
}
return f[n] * 10 >= n * 9;
}
int main()
{
int T , m , i , j , len , p , l , r , mid , ans;
scanf("%d%d" , &T , &m);
for(i = 1 ; i <= m ; i ++ )
{
scanf("%s" , str + 1) , len = strlen(str + 1) , last = 1;
for(j = 1 ; j <= len ; j ++ ) ins(str[j] - '0');
}
while(T -- )
{
scanf("%s" , str + 1) , n = strlen(str + 1);
for(p = i = 1 , len = 0 ; i <= n ; i ++ )
{
if(next[p][str[i] - '0']) len ++ , p = next[p][str[i] - '0'];
else
{
while(p && !next[p][str[i] - '0']) p = fa[p];
if(p) len = dis[p] + 1 , p = next[p][str[i] - '0'];
else len = 0 , p = 1;
}
mx[i] = len;
}
l = 1 , r = n , ans = 0;
while(l <= r)
{
mid = (l + r) >> 1;
if(judge(mid)) ans = mid , l = mid + 1;
else r = mid - 1;
}
printf("%d\n" , ans);
}
return 0;
}


posted @ 2017-07-04 10:43  GXZlegend  阅读(393)  评论(0编辑  收藏  举报