2806: [Ctsc2012]Cheat

题目:传送门


题解:

   感觉这题考的更多的就是DP啊...

   看完题目的第一反应就是广义SAM...(然而并不会)

   再YY一会儿想起来可以直接将作文库连成一个母串(中间用2隔开)去跑SAM,然后直接把文章当成是子串在自动机上面跑(字符串匹配问题的套路啊)

   考虑DP:设f[i]表示前i个位置的最大匹配长度。那么f[i]=max(f[i],f[j]+i-j);

   直接DP肯定爆炸,再考虑利用SAM来预处理一个match[],match[i]表示当前文章以第i个位置结尾的子串和作文库匹配的最长长度(直接在自动机里面乱跑)

   L满足而分性,直接二分,然后我们会发现对于f[i]有影响的其实只在于[i-match[i],i-L],i-L这个玩意肯定单调递增啊...

   一波单调队列直接搞:对于队头,如果位置在合法区间内,则直接可以找到最优解来更新f[i]

   槽点:一开始被卡精度...%AC_Artist.zig_zag之后又WA了...然后发现自己脑残在check里memset。。。(做了一上午...菜啊),数据真的有点水

  


代码:

 #include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
struct SAM
{
int son[],fail,dep;
SAM(){memset(son,,sizeof(son));fail=dep=;}
}ch[];int a[],match[],root,cnt,last;
int n,m;
char s[],st[];
void add(int k)
{
int x=a[k];
int p=last,np=++cnt;ch[np].dep=ch[p].dep+;
while(p && ch[p].son[x]==)ch[p].son[x]=np,p=ch[p].fail;
if(p==)ch[np].fail=root;
else
{
int q=ch[p].son[x];
if(ch[q].dep==ch[p].dep+)ch[np].fail=q;
else
{
int nq=++cnt;ch[nq]=ch[q];
ch[nq].dep=ch[p].dep+;
ch[np].fail=ch[q].fail=nq;
while(p && ch[p].son[x]==q)ch[p].son[x]=nq,p=ch[p].fail;
}
}
last=np;
}
void get_match(int len)
{
int p=root,sum=;
for(int i=;i<=len;i++)
{
int x=s[i]-'';
if(ch[p].son[x]!=)sum++,p=ch[p].son[x];
else //失配了就跳fail
{
while(p && ch[p].son[x]==)p=ch[p].fail;
if(p==)p=root,sum=;
else sum=ch[p].dep+,p=ch[p].son[x];
}
match[i]=sum;
}
}
int f[],list[];
bool check(int L,int len)
{
//if(L==0)return true;
f[]=;list[]=;
int p,head=,tail=;
for(int i=;i<=len;i++)
{
f[i]=f[i-];p=i-L;if(p<)continue;
while(head<=tail && f[p]+i-p>f[list[tail]]+i-list[tail])tail--;list[++tail]=p;
while(head<=tail && list[head]<i-match[i])head++;
if(head<=tail)f[i]=max(f[i],f[list[head]]+i-list[head]);
}
double anss=double(f[len])/double(len);
return anss>=0.8999999999;
}
int main()
{
scanf("%d%d",&n,&m);int la=;
cnt=;root=last=++cnt;
for(int i=;i<=m;i++)
{
scanf("%s",st+);int len=strlen(st+);int k=;
for(int j=la;j<=len+la-;j++)
{
k++;a[j]=st[k]-'';
add(j);
}
if(i!=m){la=len+la;a[la]=;add(la);la++;}
}
while(n--)
{
scanf("%s",s+);int len=strlen(s+);
get_match(len);
int l=,r=len,ans=;
while(l<=r)
{
int mid=(l+r)/;
if(check(mid,len))ans=mid,l=mid+;
else r=mid-;
}
printf("%d\n",ans);
}
return ;
}

bzoj2806: [Ctsc2012]Cheat(SAM+DP)的更多相关文章

  1. [bzoj2806][Ctsc2012]Cheat(后缀自动机(SAM)+二分答案+单调队列优化dp)

    偷懒直接把bzoj的网页内容ctrlcv过来了 2806: [Ctsc2012]Cheat Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1943   ...

  2. BZOJ2806:[CTSC2012]Cheat(广义SAM,二分,DP)

    Description Input 第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库的行数 接下来M行的01串,表示标准作文库 接下来N行的01串,表示N篇作文 Output N行,每行一 ...

  3. BZOJ2806 [Ctsc2012]Cheat 【后缀自动机 + 二分 + 单调队列优化DP】

    题目 输入格式 第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库 的行数 接下来M行的01串,表示标准作文库 接下来N行的01串,表示N篇作文 输出格式 N行,每行一个整数,表示这篇作文的 ...

  4. BZOJ2806: [Ctsc2012]Cheat(广义后缀自动机,单调队列优化Dp)

    Description Input 第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库的行数接下来M行的01串,表示标准作文库接下来N行的01串,表示N篇作文 Output N行,每行一个整 ...

  5. bzoj2806 [Ctsc2012]Cheat

    我们的目的就是找到一个最大的L0,使得该串的90%可以被分成若干长度>L0的字典串中的子串. 明显可以二分答案,对于二分的每个mid 我们考虑dp:f[i]表示前i个字符,最多能匹配上多少个字符 ...

  6. 【BZOJ2806】[Ctsc2012]Cheat 广义后缀自动机+二分+单调队列优化DP

    [BZOJ2806][Ctsc2012]Cheat Description Input 第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库的行数接下来M行的01串,表示标准作文库接下来N行的 ...

  7. 【BZOJ 2806】 2806: [Ctsc2012]Cheat (SAM+二分+DP+单调队列)

    2806: [Ctsc2012]Cheat Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1262  Solved: 643 Description ...

  8. bzoj 2806: [Ctsc2012]Cheat 后缀自动机DP

    2806: [Ctsc2012]Cheat Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 583  Solved: 330[Submit][Statu ...

  9. BZOJ 2806: [Ctsc2012]Cheat [广义后缀自动机 单调队列优化DP 二分]

    2806: [Ctsc2012]Cheat 题意: 多个主串和多个询问串,每次询问将询问串分成多个连续子串,如果一个子串长度>=L且在主串中出现过就是熟悉的 如果熟悉的字符串长度>=询问串 ...

随机推荐

  1. Open CASCADE Technology(OCCT)概述

    OCCT模块结构图 基础类: Foundation Classes module underlies all other OCCT classes; 模型数据: Modeling Data modul ...

  2. JS 判断数组包含某个字符

    //arrDisable 数组  infoType 字符 if($.inArray(infoType, arrDisable)) { console.log('包含'); }

  3. lua 计算字符串字符个数“中文字算一个字符”

    local function GetStringWordNum(str) local fontSize = local lenInByte = #str local count = local i = ...

  4. lua迭代

    迭代 function enum(array) local index = 1 return function() --返回迭代函数 local ret = array[index] index = ...

  5. 3) 十分钟学会android--建立第一个APP,建立简单的用户界面

    在本小节里,我们将学习如何用 XML 创建一个带有文本输入框和按钮的界面.下一节课将学会使 APP 对按钮做出响应——按钮被按下时,文本框里的内容被发送到另外一个 Activity. Android ...

  6. python第三方库 pip 豆瓣源

    pip install xxx -i http://pypi.douban.com/simple/ xxx 为包名

  7. Cocos2d-x-3.6学习笔记第一天

    系统环境: win7,python2.7 开发工具:vs2013 cocos版本:cocos2d-x-3.6 暂无模拟手机的环境 新建我的第一个cocos2d项目 1.打开cmd,cd到cocos2d ...

  8. 重载(overload)和重写(override)的对比(笔试经常出)

    Day04_SHJavaTraing_4-6-2017 1.重载(overload):    ①权限修饰符(public private 默认):        无关    ②返回值类型:       ...

  9. CUDA5.5入门文章:VS10设置

    原文链接:http://blog.csdn.net/augusdi/article/details/12205435 作者专栏:http://blog.csdn.net/augusdi/article ...

  10. Swift 字典 Dictionary基本用法

    import UIKit /* 字典的介绍 1.字典允许按照某个键访问元素 2.字典是由两部分组成, 一个键(key)集合, 一个是值(value)集合 3.键集合是不能有重复的元素, 值集合可以有重 ...