被\(mhr\)的暴力干翻了

这道题做法还是非常好想的

先做一遍差分,在每个串的某尾插入一个特殊字符,再将所有的串拼接在一起

现在的问题就转化为找到一个最长的公共子串使得其出现了\(n\)次,但是在一个串内出现多次出现只算一次

先考虑一下没有第二个限制的做法

那就是最简单的\(SA\)+二分了,就是扫一遍\(height\)数组,之后根据\(height\)进行分组使得一个组内所有的\(height\)都大于等于当前二分出来的\(mid\),之后一个组内有多少个就代表这个子串出现了多少次

现在有了限制,就是不能来自于同一个串

于是我们给每一个\(sa_i\)打一个标记,标记好其来自哪一个数组,之后对于一个组内出现的同一个串内的我们只需要算一次就够了

代码

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #define re register
  5. #define LL long long
  6. #define maxn (1000*100+1000+5)*2
  7. #define max(a,b) ((a)>(b)?(a):(b))
  8. #define min(a,b) ((a)<(b)?(a):(b))
  9. #define pt putchar(1)
  10. inline int read()
  11. {
  12. char c=getchar();int x=0;
  13. while(c<'0'||c>'9') c=getchar();
  14. while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
  15. }
  16. int a[maxn],f[maxn],c[maxn];
  17. int tp[maxn],sa[maxn],rk[maxn],tax[maxn],het[maxn],b[maxn];
  18. int n,m,K,r,t;
  19. inline void qsort()
  20. {
  21. for(re int i=0;i<=K;i++) tax[i]=0;
  22. for(re int i=1;i<=n;i++) tax[rk[i]]++;
  23. for(re int i=1;i<=K;i++) tax[i]+=tax[i-1];
  24. for(re int i=n;i;--i) sa[tax[rk[tp[i]]]--]=tp[i];
  25. }
  26. inline int check(int x)
  27. {
  28. int num=0,now=1;
  29. if(f[sa[1]]) num++,b[f[sa[1]]]++;
  30. for(re int i=2;i<=n;i++)
  31. {
  32. if(het[i]<x)
  33. {
  34. if(num>=m) return 1;
  35. for(re int j=now;j<i;j++) b[f[sa[j]]]=0;
  36. num=0,now=i;
  37. if(f[sa[i]]) num++,b[f[sa[i]]]++;
  38. continue;
  39. }
  40. if(!b[f[sa[i]]]&&f[sa[i]]) b[f[sa[i]]]++,num++;
  41. }
  42. return num>=m;
  43. }
  44. int main()
  45. {
  46. m=read();
  47. for(re int i=1;i<=m;i++)
  48. {
  49. t=read();r=max(t,r);
  50. for(re int j=1;j<=t;j++) a[++n]=read(),f[n]=i;
  51. a[++n]=i+101,f[n]=0;
  52. }
  53. for(re int i=1;i<=n;i++) c[i]=a[i]-a[i-1];
  54. for(re int i=1;i<=n;i++) c[i]+=2001,K=max(c[i],K);
  55. c[1]=0;
  56. for(re int i=1;i<=n;i++) tp[i]=i,rk[i]=c[i];
  57. qsort();
  58. for(re int w=1,p=0;p<n;K=p,w<<=1)
  59. {
  60. p=0;
  61. for(re int i=1;i<=w;i++) tp[++p]=n-w+i;
  62. for(re int i=1;i<=n;i++) if(sa[i]>w) tp[++p]=sa[i]-w;
  63. qsort();
  64. for(re int i=1;i<=n;i++) std::swap(rk[i],tp[i]);
  65. rk[sa[1]]=p=1;
  66. for(re int i=2;i<=n;i++) rk[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w])?p:++p;
  67. }
  68. int k=0;
  69. for(re int i=1;i<=n;i++)
  70. {
  71. if(k) --k;
  72. int j=sa[rk[i]-1];
  73. while(c[i+k]==c[j+k]) ++k;
  74. het[rk[i]]=k;
  75. }
  76. int l=1,ans=0;
  77. while(l<=r)
  78. {
  79. int mid=l+r>>1;
  80. if(check(mid)) l=mid+1,ans=mid;
  81. else r=mid-1;
  82. }
  83. printf("%d\n",ans+1);
  84. return 0;
  85. }

【[SDOI2008]Sandy的卡片】的更多相关文章

  1. BZOJ 4698: Sdoi2008 Sandy的卡片

    4698: Sdoi2008 Sandy的卡片 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 106  Solved: 40[Submit][Stat ...

  2. BZOJ 4698: Sdoi2008 Sandy的卡片 [后缀自动机]

    4698: Sdoi2008 Sandy的卡片 题意:差分后就是多个串LCS SAM+map大法好 模板打错 智力-2 #include <iostream> #include <c ...

  3. 洛谷 P2463 [SDOI2008]Sandy的卡片 解题报告

    P2463 [SDOI2008]Sandy的卡片 题意 给\(n(\le 1000)\)串,定义两个串相等为"长度相同,且一个串每个数加某个数与另一个串完全相同",求所有串的最长公 ...

  4. bzoj4698 / P2463 [SDOI2008]Sandy的卡片

    P2463 [SDOI2008]Sandy的卡片 直接二分长度暴力匹配....... 跑的还挺快 (正解是后缀数组的样子) #include<iostream> #include<c ...

  5. 【BZOJ4698】Sdoi2008 Sandy的卡片 后缀数组+RMQ

    [BZOJ4698]Sdoi2008 Sandy的卡片 Description Sandy和Sue的热衷于收集干脆面中的卡片.然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡 ...

  6. 【BZOJ4698】[SDOI2008]Sandy的卡片

    [BZOJ4698][SDOI2008]Sandy的卡片 题面 flag倒了. bzoj 洛谷 题解 首先题目的区间加很丑对吧, 将每个串差分一下,就可以转化为 求: 给定\(N\)个串,求他们的最长 ...

  7. P2463 [SDOI2008]Sandy的卡片[差分+串拼接后缀数组]

    P2463 [SDOI2008]Sandy的卡片 套路都差不多,都是差分后二分答案找lcp.只是这题要把多个串拼接起来成为一个大串,中间用某些值域中没有的数字相隔(最好间隔符都不一样想想为什么),排序 ...

  8. [bzoj4698][Sdoi2008]Sandy的卡片_后缀数组_二分/单调队列_双指针

    Sandy的卡片 bzoj-4698 Sdoi-2008 题目大意:题目链接. 注释:略. 想法: 这个题跟一个Usaco的题特别像.我们把这些串差分 现在我们要求的就是公共子串且出现次数不少于$k$ ...

  9. [SDOI2008]Sandy的卡片

    题目描述 Sandy和Sue的热衷于收集干脆面中的卡片. 然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡片兑换超炫的人物模型. 每一张卡片都由一些数字进行标记,第i张卡片的 ...

  10. 4698. [SDOI2008]Sandy的卡片【后缀数组】

    Description Sandy和Sue的热衷于收集干脆面中的卡片.然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积 攒卡片兑换超炫的人物模型.每一张卡片都由一些数字进行标记, ...

随机推荐

  1. php 数组任意位置插入值

    array_splice() $arr = array('A', 'B', 'C'); $arr2 = 'abc';$t = array_splice($arr, 1, 0, $arr2); prin ...

  2. SVG 旋转图形实例

    本实例展示如何在SVG中画出一个正方形并使之旋转.运行结果如下图所示: 在文本框中输入时间间隔,单位是毫秒.点击Start按钮,蓝色方块就会开始转动,每个时间间隔变化一度.变换的角度在下面的Angle ...

  3. 三:SQL server基础

    /一:创建数据库/ use master if exists (select * from sysdatabases where name='数据库名称') drop database 数据库名称 - ...

  4. 工作经验:Java 系统记录调用日志,并且记录错误堆栈

    前言:现在有一个系统,主要是为了给其他系统提供数据查询接口的,这个系统上线不会轻易更新,更不会跟随业务系统的更新而更新(这也是有一个数据查询接口系统的原因,解耦).这时,这个系统就需要有一定的方便的线 ...

  5. 思维导图_Python_内置函数

  6. JS获取第二个横杠后面的内容

    假设数据为: let str = "zheng-shize-zsz"; 获取第一个横杠的位置: str.indexOf("-") 1. 那获取第二个横杠怎么写呢 ...

  7. JavaScript的进阶之路(七)客户端JavaScript知识点总结

    一.客户端JavaScript主要是BOM DOM的操作和js脚本的兼容性.互用性.可访问性.安全性的应用.以及一些框架的引用. 二.BOM:浏览器对象模型 主要介绍window对象 1.定时器:se ...

  8. baidu地图api , 地理位置转 经纬度接口

    更多可以查看    http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-geocoding 地理编码示例: 以下是关于地理编 ...

  9. Signal & Slot in Qt

    Try your best to provide an mechanism to implement what you want. 1. All is generated by QT Framewor ...

  10. Linked List Cycle 判断一个链表是否存在回路(循环)

    Given a linked list, determine if it has a cycle in it. Follow up:Can you solve it without using ext ...