题意

给出一些母01串,多次询问,每次询问一个01串,问一个最大的\(L\),使得可以在询问串中选出若干个不相交的,长度大于等于\(L\)的子串,这些子串都在母串中出现过,且子串的长度和大于等于询问串总长的\(90\%\) 。

文件大小小于等于1100000字节。

分析

首先如果一个\(L\)可行,那么小于\(L\)的也是可行的,因为是“长度大于等于”。于是我们就二分这个\(L\),转化成判定问题。

把分割序列这类问题可以考虑dp。设\(f_i\)为前\(i\)位能分割出来符合要求的最大子串长度和。显然有:

\[f_i=\max \begin{cases}
f_{i-1} \\
f_j+(i-j) && i-j\in [g_i,L]
\end{cases}
\]

第一种情况表示从前一个直接转移过来,即不以\(i\)结尾的。第二种表示以\(i\)结尾的,其中\(g_i\)表示第\(i\)位前面最多可以在母串中匹配多长。这可以通过广义后缀自动机方便地算出来(跳link重置为len,匹配加一)。

显然如果直接暴力dp的话是\(O(n^2)\)的,必须考虑优化。只考虑第二种情况:

\[\begin{aligned}
f_i=f_j+i-j && i-j\in [g_i,L] \\
f_i=i+(f_j-j) && j\in[i-g_i,i-L]
\end{aligned}
\]

可以注意到,\(i-L\)每次往后移动一格,而\(i-g_i\)的值是单调不减的,因为每次\(i\)加一,\(g_i\)最多加一,即最多多匹配一位,不可能突然多出来匹配的几位,否则就会与前面的\(g\)值矛盾。这就是说,\(j\)的可行区间是单调不减的,所以可以用单调队列优化到\(O(n)\)。队列为队头小,队尾大,每次在队头插入\(i-L\)处的值,如果队头比它小就弹出。在队尾把出了合法区间中的值弹出,取队尾即可。

单次询问的复杂度为\(O(len\log len)\)。

代码

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. using namespace std;
  5. const int maxn=1.1e6+10;
  6. const int maxc=2;
  7. char s[maxn];
  8. int f[maxn],g[maxn],n,que[maxn],ql,qr;
  9. struct SAM {
  10. int t[maxn<<1][maxc],len[maxn<<1],link[maxn<<1],last,tot;
  11. SAM ():tot(1) {}
  12. void reset() {last=1;}
  13. void add(int x) {
  14. if (t[last][x]) {
  15. int p=t[last][x];
  16. if (len[p]==len[last]+1) {
  17. last=p;
  18. return;
  19. } else {
  20. int q=++tot;
  21. len[q]=len[last]+1;
  22. memcpy(t[q],t[p],sizeof t[p]);
  23. for (int j=last;j && t[j][x]==p;j=link[j]) t[j][x]=q;
  24. link[q]=link[p],link[p]=q;
  25. last=q;
  26. return;
  27. }
  28. }
  29. int nw=++tot,i;
  30. len[nw]=len[last]+1;
  31. for (i=last;i && !t[i][x];i=link[i]) t[i][x]=nw;
  32. if (i) {
  33. int p=t[i][x];
  34. if (len[p]==len[i]+1) link[nw]=p; else {
  35. int q=++tot;
  36. len[q]=len[i]+1;
  37. memcpy(t[q],t[p],sizeof t[p]);
  38. for (int j=i;j && t[j][x]==p;j=link[j]) t[j][x]=q;
  39. link[q]=link[p],link[p]=link[nw]=q;
  40. }
  41. } else link[nw]=1;
  42. last=nw;
  43. }
  44. void prepare() {
  45. int now=1,mat=0;
  46. for (int i=1;i<=n;++i) {
  47. int x=s[i]-'0';
  48. while (now!=1 && !t[now][x]) now=link[now],mat=len[now];
  49. if (t[now][x]) now=t[now][x],++mat;
  50. g[i]=mat;
  51. }
  52. }
  53. } sam;
  54. bool dp(int L) {
  55. ql=1,qr=0;
  56. for (int i=L;i<=n;++i) {
  57. f[i]=f[i-1];
  58. while (ql<=qr && f[que[qr]]-que[qr]<f[i-L]-i+L) --qr;
  59. que[++qr]=i-L;
  60. while (ql<=qr && que[ql]<i-g[i]) ++ql;
  61. if (ql<=qr) f[i]=max(f[i],f[que[ql]]+i-que[ql]);
  62. }
  63. return 10*f[n]>=9*n;
  64. }
  65. int main() {
  66. #ifndef ONLINE_JUDGE
  67. freopen("test.in","r",stdin);
  68. #endif
  69. int q,m;
  70. scanf("%d%d",&q,&m);
  71. for (int i=1;i<=m;++i) {
  72. scanf("%s",s+1);
  73. int len=strlen(s+1);
  74. sam.reset();
  75. for (int i=1;i<=len;++i) sam.add(s[i]-'0');
  76. }
  77. while (q--) {
  78. scanf("%s",s+1);
  79. n=strlen(s+1);
  80. memset(g,0,(sizeof g[0])*(n+1));
  81. sam.prepare();
  82. int l=1,r=n,ans;
  83. while (l<=r) {
  84. int mid=(l+r)>>1;
  85. memset(f,0,(sizeof f[0])*(n+1));
  86. if (dp(mid)) ans=mid,l=mid+1; else r=mid-1;
  87. }
  88. printf("%d\n",ans);
  89. }
  90. return 0;
  91. }

CTSC2012-Cheat的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. bzoj2806: [Ctsc2012]Cheat(SAM+DP)

    2806: [Ctsc2012]Cheat 题目:传送门 题解: 感觉这题考的更多的就是DP啊... 看完题目的第一反应就是广义SAM...(然而并不会) 再YY一会儿想起来可以直接将作文库连成一个母 ...

  7. bzoj 2806: [Ctsc2012]Cheat

    传送门 好久没刷bzoj惹…… 题意不说可以嘛. 首先二分答案. SAM的事情搞完以后就是dp辣. 我们已经对于每个位置i,找到了最小的一个k,使得[k,i]这个子串在模版串中出现过.那么我们需要做的 ...

  8. bzoj2806 [Ctsc2012]Cheat

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

  9. bzoj 2806 [Ctsc2012]Cheat——广义后缀自动机+单调队列优化DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2806 只想着怎么用后缀数据结构做,其实应该考虑结合其他算法. 可以二分那个长度 L .设当前 ...

  10. BZOJ.2806.[CTSC2012]Cheat(广义后缀自动机 DP 单调队列)

    题目链接 首先二分答案L.然后就是判断能否将原串划分出一些长度不小于L的子串,这些子串要是给定n个串中的某个串的子串,且满足它们的长度之和不小于原串长度的90%. 贪心多长选一段什么的显然不对.老老实 ...

随机推荐

  1. 06004_Redis的启动、使用和停止

    1.Redis的启动 (1)前端模式启动 ①直接运行bin/redis-server将以前端模式启动:切换到 /usr/local/redis/bin目录下,然后./redis-server : ②前 ...

  2. mac生成ssh公私匙

    1. cd ~/.ssh/ 2.ssh-keygen 3.id_rsa.pub文件放入git 4.私匙放进jenkins

  3. 类的扩展之 DataReader的扩展

    看了关于DataReader的扩展,发现能节省很多代码.从数据库读取数据最原始方法就是while()然后做循环,如果数据库添加一个字段那么你所有读取数据库的方法全部添加.通过扩展这个类就摆脱了这种令人 ...

  4. Spark优化一则 - 减少Shuffle

    Spark优化一则 - 减少Shuffle 看了Spark Summit 2014的A Deeper Understanding of Spark Internals,视频(要***)详细讲解了Spa ...

  5. TensorFlow深度学习实战---图像数据处理

    图像的亮度.对比度等属性对图像的影响非常大,这些因素都会影响最后的识别结构.当然,复杂的预处理过程可能会导致训练效率的下降(利用TensorFlow中多线程处理输入数据的解决方案). 同一不同的原始数 ...

  6. pytest使用笔记(一)

    使用环境及预置条件:pycharm+win10+python3.6+pytest 1,创建示范的测试功能脚本,另存为test_sample.py,代码如下: # test_sample.py def ...

  7. Bug 级别定义标准

    缺陷种类 缺陷级别 详细说明 功能缺陷 Urgent (V级) 1.操作系统无法正常使用,死机,出现致命错误 2.数据丢失 3.被测试系统频繁崩溃,程序出错,使功能不能继续使用 4.性能与需求不一致 ...

  8. Unity Lighting - Choosing a Color Space 选择色彩空间(四)

      Choosing a Color Space 选择色彩空间 In addition to selecting a rendering path, it’s important to choose ...

  9. 基于腾讯云CLB实现K8S v1.10.1集群高可用+负载均衡

    概述: 最近对K8S非常感兴趣,同时对容器的管理等方面非常出色,是一款非常开源,强大的容器管理方案,最后经过1个月的本地实验,最终决定在腾讯云平台搭建属于我们的K8S集群管理平台~ 采购之后已经在本地 ...

  10. nginx配置 send_timeout 引发的js、css解析失败问题

    错误情况是web界面排版错误,js.css文件加载失败,通过调试器查看js和css文件路径都是对的,而且可访问. 业务使用的是 nginx+php+mysql+redis的架构 解决办法: 查了很多资 ...