【BZOJ4566】找相同字符(后缀数组)

题面

BZOJ

题解

后缀数组的做法,应该不是很难想

首先看到两个不同的串,当然是接在一起求\(SA,height\)

那么,考虑一下暴力

在两个串各枚举一个后缀,他们的\(lcp\)就是对答案产生的贡献

现在优化一下,按照\(SA\)的顺序枚举来处理\(lcp\)

利用一个单调栈维护一下,每次记录一下前面有多少个的贡献和当前答案一样就好啦

只是有点难写。。。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<set>
  8. #include<map>
  9. #include<vector>
  10. #include<queue>
  11. using namespace std;
  12. #define MAX 440000
  13. #define ll long long
  14. int n,gr[MAX];
  15. int SA[MAX],hg[MAX],rk[MAX];
  16. int a[MAX],t[MAX],x[MAX],y[MAX];
  17. bool cmp(int i,int j,int k){return y[i]==y[j]&&y[i+k]==y[j+k];}
  18. void GetSA()
  19. {
  20. int m=50;
  21. for(int i=1;i<=n;++i)t[x[i]=a[i]]++;
  22. for(int i=1;i<=m;++i)t[i]+=t[i-1];
  23. for(int i=n;i>=1;--i)SA[t[x[i]]--]=i;
  24. for(int k=1;k<=n;k<<=1)
  25. {
  26. int p=0;
  27. for(int i=1;i<=n;++i)y[i]=0;
  28. for(int i=n-k+1;i<=n;++i)y[++p]=i;
  29. for(int i=1;i<=n;++i)if(SA[i]>k)y[++p]=SA[i]-k;
  30. for(int i=0;i<=m;++i)t[i]=0;
  31. for(int i=1;i<=n;++i)t[x[y[i]]]++;
  32. for(int i=1;i<=m;++i)t[i]+=t[i-1];
  33. for(int i=n;i>=1;--i)SA[t[x[y[i]]]--]=y[i];
  34. swap(x,y);
  35. x[SA[1]]=p=1;
  36. for(int i=2;i<=n;++i)x[SA[i]]=cmp(SA[i],SA[i-1],k)?p:++p;
  37. if(p>=n)break;
  38. m=p;
  39. }
  40. for(int i=1;i<=n;++i)rk[SA[i]]=i;
  41. for(int i=1,j=0;i<=n;++i)
  42. {
  43. if(j)--j;
  44. while(a[i+j]==a[SA[rk[i]-1]+j])++j;
  45. hg[rk[i]]=j;
  46. }
  47. }
  48. int Q1[MAX],top1,S1[MAX];
  49. int Q2[MAX],top2,S2[MAX];
  50. ll ans,sum1,sum2;
  51. char ch[MAX];
  52. int main()
  53. {
  54. scanf("%s",ch+1);
  55. for(int i=1,l=strlen(ch+1);i<=l;++i)a[++n]=ch[i]-96,gr[n]=1;
  56. a[++n]=27;
  57. scanf("%s",ch+1);
  58. for(int i=1,l=strlen(ch+1);i<=l;++i)a[++n]=ch[i]-96,gr[n]=2;
  59. GetSA();
  60. for(int i=1,tot=0;i<n;++i)
  61. {
  62. ans+=(gr[SA[i]]==1)?sum2:sum1;
  63. ll tmp1=0;
  64. while(top1&&Q1[top1]>=hg[i+1])
  65. {
  66. tmp1+=S1[top1];
  67. sum1-=1ll*(Q1[top1]-hg[i+1])*S1[top1];
  68. --top1;
  69. }
  70. ++top1;S1[top1]=tmp1;Q1[top1]=hg[i+1];
  71. ll tmp2=0;
  72. while(top2&&Q2[top2]>=hg[i+1])
  73. {
  74. tmp2+=S2[top2];
  75. sum2-=1ll*(Q2[top2]-hg[i+1])*S2[top2];
  76. --top2;
  77. }
  78. ++top2;S2[top2]=tmp2;Q2[top2]=hg[i+1];
  79. if(gr[SA[i]]==1)++S1[top1],sum1+=hg[i+1];
  80. else ++S2[top2],sum2+=hg[i+1];
  81. }
  82. printf("%lld\n",ans);
  83. return 0;
  84. }

【BZOJ4566】找相同字符(后缀数组)的更多相关文章

  1. 【BZOJ4566】[Haoi2016]找相同字符 后缀数组+单调栈

    [BZOJ4566][Haoi2016]找相同字符 Description 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两 个子串中有一个位置不同 ...

  2. [HAOI2016] 找相同字符 - 后缀数组,单调栈

    [HAOI2016] 找相同字符 Description 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两个子串中有一个位置不同. \(n,m \l ...

  3. BZOJ.4566.[HAOI2016]找相同字符(后缀数组 单调栈)

    题目链接 给定两个字符串,求它们有多少个相同子串.相同串的位置不同算多个. POJ3145简化版. 后缀自动机做法见这儿,又快又好写(一下就看出差距了..) //13712kb 4076ms #inc ...

  4. [BZOJ4566][Haoi2016]找相同字符 后缀自动机+dp

    4566: [Haoi2016]找相同字符 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1212  Solved: 694[Submit][Stat ...

  5. BZOJ 4566: [Haoi2016]找相同字符 [后缀自动机]

    4566: [Haoi2016]找相同字符 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 275  Solved: 155[Submit][Statu ...

  6. BZOJ 4566 JZYZOJ 1547 [haoi2016T5]找相同子串 后缀数组 并查集

    http://172.20.6.3/Problem_Show.asp?id=1547 http://www.lydsy.com/JudgeOnline/problem.php?id=4566 单纯后缀 ...

  7. BZOJ4566: [Haoi2016]找相同字符(后缀自动机)

    题意 题目链接 Sol 直接在SAM上乱搞 枚举前缀,用SAM统计可以匹配的后缀,具体在匹配的时候维护和当前节点能匹配的最大值 然后再把parent树上的点的贡献也统计上,这部分可以爆跳parent树 ...

  8. bzoj4566 找相同字符

    题意:给定两个字符串,从中各取一个子串使之相同,有多少种取法.允许本质相同. 解:建立广义后缀自动机,对于每个串,分别统计cnt,之后每个点的cnt乘起来.记得开long long #include ...

  9. HAOI2016 找相同字符 后缀自动机

    两个串,考虑一建一跑.枚举模式串的位置\(i\),考虑每次统计以\(i\)结尾的所有符合要求的串.在后缀自动机上走时记录当前匹配长度\(curlen\),则当前节点的贡献是\((curlen-len[ ...

  10. bzoj4566 / P3181 [HAOI2016]找相同字符

    P3181 [HAOI2016]找相同字符 后缀自动机 (正解应是广义后缀自动机) 并不会广义后缀自动机. 然鹅可以用普通的后缀自动机.   我们先引入一个问题:算出从一个串内取任意两个不重合子串完全 ...

随机推荐

  1. 阿里云CentOS使用iptables禁止某IP访问

    在CentOS下封停IP,有封杀网段和封杀单个IP两种形式.一般来说,现在的攻击者不会使用一个网段的IP来攻击(太招摇了),IP一般都是散列的.于是下面就详细说明一下封杀单个IP的命令,和解封单个IP ...

  2. 写好Java代码的30条经验总结(转)

    成为一个优秀的Java程序员,有着良好的代码编写习惯是必不可少的.下面就让我们来看看代码编写的30条建议吧. (1) 类名首字母应该大写.字段.方法以及对象(句柄)的首字母应小写.对于所有标识符,其中 ...

  3. SpringBoot 中常用注解

    本篇博文将介绍几种SpringBoot 中常用注解 其中,各注解的作用为: @PathVaribale 获取url中的数据 @RequestParam 获取请求参数的值 @GetMapping 组合注 ...

  4. Duilib第一步(II)-Hello World

    My first Duilib program 1. Prepare for development 打开DuiFarm项目DuiFarm.cpp文件,将除_tWinMain函数之外所有内容删除.删除 ...

  5. NumPy学习_00 ndarray的创建

    1.使用array()函数创建数组 参数可以为:单层或嵌套列表:嵌套元组或元组列表:元组或列表组成的列表 # 导入numpy库 import numpy as np # 由单层列表创建 a = np. ...

  6. 如何使用supervisor管理你的应用

    1.前言 Supervisor(http://supervisord.org/)是用Python开发的一个client/server服务,是UNIX-like系统下的一个进程管理工具,不支持Windo ...

  7. 在kali安装中文输入法的教程

    1终端下vi /etc/apt/sources.list  修改镜像元  (按E进行编辑 具体实例不同可能没有)  按 i进入编辑 擦除原有的几个官方源改为deb http://mirrors.ali ...

  8. CodeForces-749A

    要求组成n的素数最多,根据n的奇偶讨论:如果n是偶数,直接打印n/2个数字'2'就可以了:如果n是基数,则先打印一个'3',再打印(n-3)/2个数字'2'就可以了. AC代码: #include&l ...

  9. BZOJ2820 - 巧克力王国

    原题链接 Description 给出个二维平面上的点,第个点为,权值为.接下来次询问,给出,求所有满足的点的权值和. Solution 对于这个点建一棵k-d树,子树维护一个子树和. 如果子树所代表 ...

  10. 使用phpstorm提交svn代码版本管理系统遇到的问题解决办法

    1.当自己提交代码的时候显示out of date的时候,表示我们本地的代码过时啦,需要更新一下再提交. 即:更新一下再提交即可. 2.当自己的代码和服务器上的冲突的时候,我们右键点击冲突的文件,选择 ...