zoukankan      html  css  js  c++  java
  • bzoj2806: [Ctsc2012]Cheat

    地址:http://www.lydsy.com/JudgeOnline/problem.php?id=2806

    题目:

    2806: [Ctsc2012]Cheat

    Time Limit: 20 Sec  Memory Limit: 256 MB
    Submit: 1457  Solved: 738

    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%

    思路:

      对标准串建立广义后缀自动机,然后让作文串在上面跑,记录长度每个位置所能匹配的最长长度,记为mx[i].

      求L0的过程显然可以二分,然后用dp判断是否可行。

      dp转移很容易可以得到:dp[i]=max(dp[i-1],max(dp[j]+i-j))   i-mx[i]<=j<=i-L

      如果直接dp复杂度极限是O(n^2),显然TLE。

      观察dp方程可以发现 dp[j] - j 部分和i无关,且 i - mx[i] i - L是不递减的。

      所以可以通过维护个值递增的单调队列优化。

      广义后缀自动机就是插入一个串后把last标回root,然后插入下一个串。

      1 /**************************************************************
      2     Problem: 2806
      3     User: weeping
      4     Language: C++
      5     Result: Accepted
      6     Time:976 ms
      7     Memory:68676 kb
      8 ****************************************************************/
      9  
     10 #include <bits/stdc++.h>
     11 using namespace std;
     12 struct SAM
     13 {
     14     static const int MAXN = 1000001<<1;//大小为字符串长度两倍
     15     static const int LetterSize = 2;
     16  
     17     int tot, last, ch[MAXN][LetterSize], fa[MAXN], len[MAXN];
     18     int sum[MAXN], tp[MAXN], cnt[MAXN]; //sum,tp用于拓扑排序,tp为排序后的数组
     19  
     20     void init( void)
     21     {
     22         last = tot = 1;
     23         len[1] = 0;
     24         memset( ch[1], 0, sizeof ch[1]);
     25     }
     26  
     27     void add( int x)
     28     {
     29         int p = last, np = last = ++tot;
     30         len[np] = len[p] + 1, cnt[np] = 1;
     31         memset( ch[np], 0, sizeof ch[np]);
     32         while( p && !ch[p][x]) ch[p][x] = np, p = fa[p];
     33         if( p == 0)
     34             fa[np] = 1;
     35         else
     36         {
     37             int q = ch[p][x];
     38             if( len[q] == len[p] + 1)
     39                 fa[np] = q;
     40             else
     41             {
     42                 int nq = ++tot;
     43                 memcpy( ch[nq], ch[q], sizeof ch[q]);
     44                 len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
     45                 while( p && ch[p][x] == q)  ch[p][x] = nq, p = fa[p];
     46             }
     47         }
     48     }
     49  
     50     void toposort( void)
     51     {
     52         for(int i = 1; i <= len[last]; i++)   sum[i] = 0;
     53         for(int i = 1; i <= tot; i++)   sum[len[i]]++;
     54         for(int i = 1; i <= len[last]; i++)   sum[i] += sum[i-1];
     55         for(int i = 1; i <= tot; i++)   tp[sum[len[i]]--] = i;
     56         for(int i = tot; i; i--)   cnt[fa[tp[i]]] += cnt[tp[i]];
     57     }
     58  
     59     int mx[1000002],q[1000001],dp[1000001];
     60     bool check(int x,int slen)
     61     {
     62         if(!x) return 1;
     63         int st=0,se=0;
     64         for(int i=0;i<x;i++)   dp[i]=0;
     65         for(int i=1;i<=slen;i++)
     66         {
     67             while(st>se&&i-x>0&&dp[q[st]]-q[st]<=dp[i-x]-(i-x))    st--;
     68             if(i-x<0)   continue;
     69             q[++st]=i-x;
     70             while(st>se&&q[se+1]<i-mx[i]) se++;
     71             dp[i]=dp[i-1];
     72             if(st>se)
     73                 dp[i]=max(dp[i],dp[q[se+1]]-q[se+1]+i);
     74         }
     75         if(dp[slen]*10>=9*slen)   return 1;
     76         return 0;
     77     }
     78     void go(char *ss)
     79     {
     80         int slen=strlen(ss+1);
     81         for(int i=1,p=1,num=0;i<=slen;i++)
     82         {
     83             int c=ss[i]-'0';
     84             if(ch[p][c])   p=ch[p][c],num++;
     85             else
     86             {
     87                 while(p&&!ch[p][c]) p=fa[p];
     88                 if(!p) p=1,num=0;
     89                 else    num=len[p]+1,p=ch[p][c];
     90             }
     91             mx[i]=num;
     92         }
     93         int l=0,r=slen,ans;
     94         while(l<=r)
     95         {
     96             int mid=l+r>>1;
     97             if(check(mid,slen))  ans=mid,l=mid+1;
     98             else    r=mid-1;
     99         }
    100         printf("%d
    ",ans);
    101     }
    102 } sam;
    103 char ss[1000001];
    104 int main(void)
    105 {
    106     //freopen("in.acm","r",stdin);
    107     int n,m;
    108     cin>>m>>n;
    109     sam.init();
    110     for(int i=1;i<=n;i++,sam.last=1)
    111     {
    112         scanf("%s",ss);
    113         for(int j=0,len=strlen(ss);j<len;j++)   sam.add(ss[j]-'0');
    114     }
    115     for(int i=1;i<=m;i++)
    116         scanf("%s",ss+1),sam.go(ss);
    117     return 0;
    118 }
  • 相关阅读:
    组合,多态,封装
    继承and派生
    面向对象编程 类 后补充了元类 和单例
    数据结构与算法(Python)
    git版本控制系统命令
    python数据类型
    MVC与MTV模型及Django请求的生命周期
    linux目录文件及系统启动知识
    linux命令汇总
    Python字符串和列表的内置方法
  • 原文地址:https://www.cnblogs.com/weeping/p/7546045.html
Copyright © 2011-2022 走看看