Luogu P4022 [CTSC2012]熟悉的文章

广义 \(SAM\) + 二分答案 + 单调队列优化 \(DP\)

对作文库建广义 \(SAM\) ,然后求出作文每个位置的最长匹配 \(d[i]\),然后二分答案 \(md\),然后 \(DP\) ,\(f[i]\) 表示到 \(i\) 的最大匹配长度,有 \(f[i]=\max(f[j]-j+i),j\in[i-d[i],i-md]\),最后检查 \(f[n]\geq 0.9\times len\)

#include<iostream>
#include<cstdio>
#include<cstring>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
  register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
  do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=2000010;
int n,m;
int d[N],f[N],q[N];
char s[N];
struct SAM {
  int tot,lst,fa[N],c[N][2],len[N];
  SAM() {tot=lst=1;}
  inline void add(int ch) {
    if(c[lst][ch]&&len[c[lst][ch]]==len[lst]+1) 
      return lst=c[lst][ch],void();
    R p=lst,np=++tot,q,nq,flg=0;
    len[np]=len[p]+1;
    while(p&&!c[p][ch]) c[p][ch]=np,p=fa[p];
    if(!p) fa[np]=1;
    else {
      q=c[p][ch];
      if(len[q]==len[p]+1) fa[np]=q;
      else {
        if(p==lst) flg=1;
        nq=++tot;
        memcpy(c[nq],c[q],8);
        fa[nq]=fa[q],len[nq]=len[p]+1;
        fa[np]=fa[q]=nq;
        while(p&&c[p][ch]==q) c[p][ch]=nq,p=fa[p];
      }
    } lst=flg?nq:np;
  }
  inline void calc() {
    R n=strlen(s+1),p=1,l=0;
    for(R i=1;i<=n;++i) {
      R ch=s[i]-48;
      while(p&&!c[p][ch]) p=fa[p],l=len[p];
      if(p) p=c[p][ch],++l;
      else p=1,l=0;
      d[i]=l;
    }
  }
}s1;
inline bool ck(int md) {
  R h=1,t=0,n=strlen(s+1);
  memset(f,0,md<<2);
  for(R i=md;i<=n;++i) {
    f[i]=f[i-1];
    while(h<=t&&f[q[t]]-q[t]<=f[i-md]-(i-md)) --t;
    q[++t]=i-md;
    while(h<=t&&q[h]<i-d[i]) ++h;
    if(h<=t) f[i]=max(f[i],i+f[q[h]]-q[h]);
  } return f[n]*10>=n*9;
}
inline void main() {
  m=g(),n=g();
  for(R i=1,len;i<=n;++i) { s1.lst=1;
    scanf("%s",s+1),len=strlen(s+1);
    for(R i=1;i<=len;++i) s1.add(s[i]-48);
  }
  for(R i=1;i<=m;++i) {
    scanf("%s",s+1);
    R l=0,r=strlen(s+1),md;
    s1.calc();
    while(l<r) {
      md=(l+r+1)>>1;
      if(ck(md)) l=md;
      else r=md-1;
    } printf("%d\n",l);
  }
}
} signed main() {Luitaryi::main(); return 0;}

2020.01.10

上一篇:LuoguP5576 [CmdOI2019]口头禅 后缀树+线段树+暴力


下一篇:Luogu P4070 [SDOI2016]生成魔咒