zoukankan      html  css  js  c++  java
  • 【BZOJ2806】Cheat 【广义后缀自动机+单调队列优化dp+二分】

    题意

      有M篇标准作文组成了一个作文库(每篇作文都是一个01的字符串),然后给出N篇作文(自然也是01字符串)。如果一个长度不小于L的串在作文库中出现过,那么它是熟悉的。对于某一篇作文,我们要把它分为若干段,使得熟悉过的字符串长度>=百分之90,我们要求满足这个条件的最小的L。

    分析

     这个L显然满足二分,然后我们要想怎么判断,对于当前L,这篇作文的熟悉过字符串的最长长度是什么。我们先把作文库建一个广义后缀自动机,然后对于每篇作文很容易可以求出一个len[i]指的是在i位置结束的子串在作文库中出现过的最长长度是多少。然后我们来dp。设f[i]为前缀i的最长熟悉长度。那么f[i]=max(f[i-1],f[j]+i-j+1|(i-L>=j>=len[i]-i))。但是这个dp是要O(n^2)的。但是我们发现,这个dp是单调的,也就是说i如果是从j递推来的,那么i+1 就不可能从j以前递推来。所以这个j我们用单调队列来维护。我们单调队列中存的是根据值f[j]-j单调的j值。

      

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <iostream>
      4 #include <algorithm>
      5 #include <queue>
      6 
      7 using namespace std;
      8 const int maxn=3000000;
      9 char s[maxn];
     10 struct state{
     11     int len,link;
     12     int next[2];
     13 }st[2*maxn];
     14 int len[maxn];
     15 int N,M,n;
     16 int last,cur,sz;
     17 void init(){
     18     sz=1;
     19     cur=last=0;
     20     st[0].link=-1;
     21     st[0].len=0;
     22 }
     23 void build_sam(int c){
     24     cur=sz++;
     25     st[cur].len=st[last].len+1;
     26     int p;
     27     for(p=last;p!=-1&&st[p].next[c]==0;p=st[p].link)
     28         st[p].next[c]=cur;
     29     if(p==-1)
     30         st[cur].link=0;
     31     else{
     32         int q=st[p].next[c];
     33         if(st[q].len==st[p].len+1){
     34             st[cur].link=q;
     35         }else{
     36             int clone=sz++;
     37             st[clone].len=st[p].len+1;
     38             st[clone].link=st[q].link;
     39             for(int i=0;i<2;i++)
     40                 st[clone].next[i]=st[q].next[i];
     41             for(;p!=-1&&st[p].next[c]==q;p=st[p].link)
     42                 st[p].next[c]=clone;
     43             st[cur].link=st[q].link=clone;
     44         }
     45     }
     46     last=cur;
     47 }
     48 int f[maxn];
     49 //dp[i]=max(dp[j]+i-j|  i-len[i]<=j<=i-L)
     50 
     51 bool check(int L){
     52     deque<int>q;
     53     for(int i=1;i<=n;i++){
     54         f[i]=f[i-1];
     55         if(i<L)continue;
     56         while(!q.empty()&&f[q.back()]-q.back()<f[i-L]-i+L)
     57             q.pop_back();
     58         q.push_back(i-L);
     59         while(!q.empty()&&q.front()<i-len[i])
     60             q.pop_front();
     61         if(!q.empty())
     62         f[i]=max(f[i],f[q.front()]+i-q.front());
     63     }
     64     return f[n]*10>=n*9;
     65 }
     66 
     67 int main(){
     68     scanf("%d%d",&N,&M);
     69     init();
     70     for(int i=1;i<=M;i++){
     71         scanf("%s",s);
     72         n=strlen(s);
     73         for(int j=0;j<n;j++){
     74             int c=s[j]-'0';
     75             build_sam(c);
     76         }
     77         last=0;
     78     }
     79     for(int q=1;q<=N;q++){
     80         scanf("%s",s+1);
     81         n=strlen(s+1);
     82         int u=0,Len=0;
     83         for(int i=1;i<=n;i++){
     84             int c=s[i]-'0';
     85             while(u!=-1&&st[u].next[c]==0){
     86                 u=st[u].link;
     87                 Len=st[u].len;
     88             }
     89             if(u==-1)
     90                 u=0,Len=0;
     91             else{
     92                 u=st[u].next[c];
     93                 Len++;
     94             }
     95             len[i]=Len;
     96         }
     97         int l=0,r=n,ans=0;
     98         while(l<=r){
     99             int mid=l+(r-l)/2;
    100             if(check(mid)){
    101                 ans=mid;
    102                 l=mid+1;
    103             }else{
    104                 r=mid-1;
    105             }
    106         }
    107         printf("%d
    ",ans);
    108     }
    109 return 0;
    110 }
    View Code
  • 相关阅读:
    基本数据结构——栈
    错误 1 error C4996: 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. d:usersvs2013le
    Java内存区域
    VS2010 无法计算HKEY_LOCAL_MACHINESOFTWAREMicrosoftMSBuildToolsVersions14.0@VCTargetPath处的属性表达式
    PHP高并发场景下的一点思路
    LINUX运维常用命令
    php7的一些新特性总结
    MySQL读写分离主从配置
    php 生成唯一id的几种解决方法
    浅谈mysql两种常用引擎MyIASM和InnoDB的区别
  • 原文地址:https://www.cnblogs.com/LQLlulu/p/9892390.html
Copyright © 2011-2022 走看看