COGS传送门

用SAM重新写了一遍..

我的方法比较笨,先把两个串连在一起,算出来相同子串个数,同理算出s1和s2的子串个数。作差即可。

至于如何统计子串个数,首先toposort后搞出right集的大小,然后$C_{|right|}^{2} \times (step[i]-step[fa])$就是答案。

  1. //BZOJ 4565
  2. //by Cydiater
  3. //2017.1.21
  4. #include <iostream>
  5. #include <cmath>
  6. #include <cstring>
  7. #include <string>
  8. #include <queue>
  9. #include <map>
  10. #include <ctime>
  11. #include <iomanip>
  12. #include <cstdlib>
  13. #include <cstdio>
  14. #include <algorithm>
  15. #include <bitset>
  16. #include <set>
  17. #include <vector>
  18. using namespace std;
  19. #define ll long long
  20. #define up(i,j,n) for(int i=j;i<=n;i++)
  21. #define down(i,j,n) for(int i=j;i>=n;i--)
  22. #define cmax(a,b) a=max(a,b)
  23. #define cmin(a,b) a=min(a,b)
  24. #define FILE "find_2016"
  25. const int MAXN=1e6+5;
  26. const int oo=0x3f3f3f3f;
  27. char s1[MAXN],s2[MAXN],s[MAXN];
  28. int len1,len2;
  29. struct SAM{
  30. int now,cnt,son[MAXN][30],step[MAXN],pre[MAXN],rnk[MAXN],label[MAXN];
  31. ll g[MAXN],ans;
  32. SAM(){now=1;cnt=1;}
  33. void Extend(int nxt){
  34. int p=now,np=++cnt;now=np;g[np]=1;
  35. step[np]=step[p]+1;
  36. for(;p&&!son[p][nxt];p=pre[p])son[p][nxt]=np;
  37. if(!p)pre[np]=1;
  38. else{
  39. int q=son[p][nxt],nq;
  40. if(step[q]==step[p]+1)pre[np]=q;
  41. else{
  42. step[(nq=++cnt)]=step[p]+1;
  43. memcpy(son[nq],son[q],sizeof(son[q]));
  44. pre[nq]=pre[q];
  45. pre[np]=pre[q]=nq;
  46. for(;son[p][nxt]==q;p=pre[p])son[p][nxt]=nq;
  47. }
  48. }
  49. }
  50. void Build(int len){
  51. up(i,1,len)Extend(s[i]-'a');
  52. }
  53. void Clear(){
  54. now=cnt=1;
  55. memset(pre,0,sizeof(pre));
  56. memset(son,0,sizeof(son));
  57. memset(step,0,sizeof(step));
  58. memset(g,0,sizeof(g));
  59. memset(label,0,sizeof(label));
  60. memset(rnk,0,sizeof(rnk));
  61. }
  62. ll col(int len){
  63. //topsort
  64. ans=0;
  65. up(i,1,cnt)label[step[i]]++;
  66. up(i,1,len)label[i]+=label[i-1];
  67. up(i,1,cnt)rnk[label[step[i]]--]=i;
  68. down(i,cnt,2){
  69. int node=rnk[i];
  70. if(g[node]>=2)
  71. ans+=(g[node]*(g[node]-1)>>1)*(ll)(step[node]-step[pre[node]]);
  72. g[pre[node]]+=g[node];
  73. }
  74. return ans;
  75. }
  76. }sam;
  77. namespace solution{
  78. void Prepare(){
  79. scanf("%s",s1+1);
  80. len1=strlen(s1+1);
  81. scanf("%s",s2+1);
  82. len2=strlen(s2+1);
  83. }
  84. void Solve(){
  85. ll ans1,ans2,ans3;
  86. memcpy(s,s1,sizeof(s));
  87. sam.Build(len1);
  88. ans1=sam.col(len1);
  89. sam.Clear();
  90. memcpy(s,s2,sizeof(s));
  91. sam.Build(len2);
  92. ans2=sam.col(len2);
  93. sam.Clear();
  94.  
  95. memcpy(s,s1,sizeof(s));
  96. s[len1+1]='a'+26;
  97. up(i,len1+2,len1+len2+1)s[i]=s2[i-len1-1];
  98. sam.Build(len1+len2+1);
  99. ans3=sam.col(len1+len2+1);
  100. //cout<<ans1<<' '<<ans2<<' '<<ans3<<endl;
  101. ans3-=ans1+ans2;
  102. cout<<ans3<<endl;
  103. }
  104. }
  105. int main(){
  106. freopen(FILE".in","r",stdin);
  107. freopen(FILE".out","w",stdout);
  108. using namespace solution;
  109. Prepare();
  110. Solve();
  111. return 0;
  112. }

看了看别人用SAM实现的代码,发现其实不必要那样。对于s1建一个sam,统计每个点的路径对应多少个子串。然后s2串在SAM上跑,经过一个点就统计上父亲点的sum(因为变换了位置)再加上当前对应的字符串的数量就行了。

[BZOJ4566][HAOI2016]找相同子串的更多相关文章

  1. BZOJ4566 [Haoi2016]找相同字符【SAM】

    BZOJ4566 [Haoi2016]找相同字符 给定两个字符串\(s和t\),要求找出两个字符串中所有可以相互匹配的子串对的数量 首先考虑可以怎么做,我们可以枚举\(t\)串的前缀\(t'\),然后 ...

  2. 字符串(后缀数组):HAOI2016 找相同子串

    [HAOI2016]找相同子串 [题目描述] 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两个子串中有一个位置不同. [输入格式] 两行,两个字符 ...

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

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

  4. [Bzoj4566][Haoi2016]找相同字符(广义后缀自动机)

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

  5. BZOJ4566: [Haoi2016]找相同字符

    Description 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两 个子串中有一个位置不同. Input 两行,两个字符串s1,s2,长度分别 ...

  6. BZOJ4566 [Haoi2016]找相同字符 字符串 SAM

    原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ4566.html 题目传送门 - BZOJ4566 题意 给定两个字符串 $s1$ 和 $s2$ ,问有 ...

  7. BZOJ4566 Haoi2016 找相同字符【广义后缀自动机】

    Description 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两 个子串中有一个位置不同. Input 两行,两个字符串s1,s2,长度分别 ...

  8. BZOJ4566:[HAOI2016]找相同字符(SAM)

    Description 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两 个子串中有一个位置不同. Input 两行,两个字符串s1,s2,长度分别 ...

  9. BZOJ4566 [Haoi2016]找相同字符 【后缀数组】

    题目 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两 个子串中有一个位置不同. 输入格式 两行,两个字符串s1,s2,长度分别为n1,n2.1 & ...

随机推荐

  1. unicode转换中文

    <!doctype html><html lang="en"> <head>  <meta http-equiv="Refres ...

  2. Python IDE软件PyCharm通用激活方法

    1,打开软件点击help-Register 2,输入地址http://xidea.online激活

  3. maven POM —— maven权威指南学习笔记(五)

    1. 简介 Archetype插件通过 pom.xml 文件创建了一个项目.这就是项目对象模型 (POM),一个项目的声明性描述. 当Maven运行一个目标的时候,每个目标都会访问定 义在项目POM里 ...

  4. remote tomcat monitor---jmc--jvisualvm

    http://mspring.org/article/1229----------jmc http://doorgods.blog.163.com/blog/static/78547857201481 ...

  5. python爬虫系列(1)——一个简单的爬虫实例

    本文主要实现一个简单的爬虫,目的是从一个百度贴吧页面下载图片. 1. 概述 本文主要实现一个简单的爬虫,目的是从一个百度贴吧页面下载图片.下载图片的步骤如下: 获取网页html文本内容:分析html中 ...

  6. DIV+CSS如何让文字垂直居中?

    在说到这个问题的时候,也许有人会问CSS中不是有vertical-align属性来设置垂直居中的吗?即使是某些浏览器不支持我只需做少许的CSS Hack技术就可以啊!所以在这里我还要啰嗦两句,CSS中 ...

  7. mysql监控优化(一)连接数和缓存

    一.mysql的连接数 MYSQL数据库安装完成后,默认最大连接数是100,一般流量稍微大一点的论坛或网站这个连接数是远远不够的,连接数少的话,在大并发下连接数会不够用,会有很多线程在等待其他连接释放 ...

  8. jetBrains设置appium环境

  9. Objective-C中的alloc和init问题

    从开始学的NSString *name=[[NSString alloc] init] 起,仅仅这句话是分配内存空间,一直在用,从来没考虑过它的内部是怎么实现的.今天无意中看到了这一句代码: NSSt ...

  10. C# comport 打印图像

    public string GetLogo() { string logo = ""; if (!File.Exists(@"C:\bitmap.bmp")) ...