hdu 5343 MZL's Circle Zhou(后缀自动机)

题目链接:hdu 5343 MZL‘s Circle Zhou

题意:

给你两个串A,B,问从A,B中选子串x,y,问x+y可以组成多少个不同的串,x和y可以为空。

题解:

贴一个官方的题解

 1 #include<bits/stdc++.h>
 2 #define mst(a,b) memset(a,b,sizeof(a))
 3 #define F(i,a,b) for(int i=(a);i<=(b);++i)
 4 using namespace std;
 5 using ll=unsigned long long;
 6
 7 const int N=1e5+7,tyn=26,M=N*2;
 8 struct SAM{
 9     int tr[M][tyn],f[M],ml[M],ed,last,p,x,r,q;
10     int b[M],d[M]; ll cnt[M];
11     inline int gid(char x){return x-‘a‘;}
12     inline void nc(int s,int &p){
13         ml[p=++ed]=s,f[ed]=cnt[ed]=0,mst(tr[ed],0);
14     }
15     void clear(){ed=0,nc(0,last);}
16     void add(int w){
17         nc(ml[x=last]+1,p),last=p,cnt[p]=1;
18         while(x&&!tr[x][w])tr[x][w]=p,x=f[x];
19         if(!x)f[p]=1;
20         else if(ml[x]+1==ml[q=tr[x][w]])f[p]=q;
21         else{
22             nc(ml[x]+1,r),f[r]=f[q],f[p]=f[q]=r;
23             memcpy(tr[r],tr[q],sizeof(tr[r]));
24             while(x&&tr[x][w]==q)tr[x][w]=r,x=f[x];
25         }
26     }
27     void upright(int mx=0){
28         F(i,0,ed)d[i]=0;
29         F(i,1,ed)d[mx<ml[i]?mx=ml[i]:ml[i]]++;
30         F(i,1,mx)d[i]+=d[i-1];
31         F(i,1,ed)b[d[ml[i]]--]=i;
32     }
33     void build(char *s){for(int i=1;s[i];i++)add(gid(s[i]));}
34 }sam[2];
35
36
37 char s[N];
38 int t;
39
40 void work()
41 {
42     for(int i=sam[1].ed;i;--i)
43     {
44         int x=sam[1].b[i];
45         sam[1].cnt[x]=1;
46         F(j,0,25)
47         {
48             int v=sam[1].tr[x][j];
49             if(v)sam[1].cnt[x]+=sam[1].cnt[v];
50         }
51     }
52 }
53
54 void solve()
55 {
56     for(int i=sam[0].ed;i;--i)
57     {
58         int x=sam[0].b[i];
59         sam[0].cnt[x]=0;
60         F(j,0,25)
61         {
62             int v=sam[0].tr[x][j];
63             if(v)sam[0].cnt[x]+=sam[0].cnt[v];
64             else sam[0].cnt[x]+=sam[1].cnt[sam[1].tr[1][j]];
65         }
66     }
67     ll ans=sam[0].cnt[1];//x为空的时候已经统计过了
68     F(i,2,sam[0].ed)ans+=sam[0].ml[i]-sam[0].ml[sam[0].f[i]];//y为空的时候
69     printf("%llu\n",ans+1);//+1表示x和y都为空的时候
70 }
71
72 int main(){
73     scanf("%d",&t);
74     while(t--)
75     {
76         scanf("%s",s+1);
77         sam[0].clear(),sam[0].build(s),sam[0].upright();
78         scanf("%s",s+1);
79         sam[1].clear(),sam[1].build(s),sam[1].upright();
80         work();solve();
81     }
82     return 0;
83 }

hdu 5343 MZL's Circle Zhou(后缀自动机)

时间: 2024-10-14 16:36:21

hdu 5343 MZL's Circle Zhou(后缀自动机)的相关文章

HDOJ 5343 MZL&#39;s Circle Zhou 后缀自动机

对第二个串建SAM求出第二个串的以每个字符开头的不同子串的数目.. 再对第一个串建SAM,遍历自动机如果某个节点后面没有某个字符则答案加上这个节点的出现次数乘上以这个字符为开头的在第二个串中的不同子串的数目.. MZL's Circle Zhou Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 244    Accepted Sub

【后缀自动机】HDU 5343 MZL&#39;s Circle Zhou

通道 题意:从A,B分别取出子串X,Y,求多少种不同的X+Y 思路: 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAX_N = 200007; typedef unsigned long long ll; struct SAM { int val[MAX_N], fa[MAX_N], c[26][MAX_N]; int tot,

HDU 5343 MZL&#39;s Circle Zhou

MZL's Circle Zhou Time Limit: 1000ms Memory Limit: 131072KB This problem will be judged on HDU. Original ID: 534364-bit integer IO format: %I64d      Java class name: Main MZL's Circle Zhou is good at solving some counting problems. One day, he comes

hdu 5343 MZL&#39;s Circle Zhou SAM

MZL's Circle Zhou 题意:给定两个长度不超过a,b(1 <= |a|,|b| <= 90000),x为a的连续子串,b为y的连续子串(x和y均可以是空串):问x+y形成的不同串的个数? 误区:开始一门心思想着求出总的可形成的字符串个数,再减去a,b中相同的子串重叠的部分:想通过连续插入a+b得到的SAM并不能获得信息:因为x,y是任意的子串,连续插入导致一定是a的后缀和b的前缀 正解:直接在计算有不同子串时,就不去计算重复的 <=>对于一个可能出现x后缀和y前缀相同

hdu 4416 Good Article Good sentence(后缀自动机)

题目链接:hdu 4416 Good Article Good sentence 题意: 给你一个串A和n个串B,问你A有多少个子串不是这n个B的子串. 题解: 将A串建立后缀自动机,对于每个B串都拿去匹配一下,并记录后缀自动机中每个节点的最大匹配长度. 然后拓扑排序,更新每个节点的fail节点.最后对于每个节点的贡献就是ml[i]-max(is[i],mx[f[i]]) (is[i]是该节点的最大匹配长度) 1 #include<bits/stdc++.h> 2 #define F(i,a,

HDU 6194 string string string(后缀自动机)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3238 [题目大意] 给出一个字符串求其出现恰好k次的子串数量 [题解] 对串建立AC自动机,所有right值为k的节点的value值的和就是答案 [代码] #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=200010; cha

HDU 4622 Reincarnation(后缀自动机)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=4622 [题目大意] 给出一个长度不超过2000的字符串,有不超过10000个询问,问[L,R]子串中出现的子串数目,相同子串不可重复计数. [题解] 考虑到字符串长度只有两千,我们对每个位置往后建立2000个后缀自动机, 这样子就能分别计算每个位置往后出现的字符串数目并保存, 对于sam上的一个节点来说,它的匹配长度与失配位置的匹配长度只差就是他们之间的子串, 所以,我们在建立sam可以同时计算

hdu 4641 K-string(后缀自动机)

题目链接:hdu 4641 K-string 题意: 一开始给你一个字符串S,现在有m个操作. 1 x表示在当前字符串末端添加一个字符x. 2 表示查询当前出现次数超过k次的子串有多少个. 题解: 后缀自动机在线维护right集. 没插入一个字符,就沿着fail跳,如果当前节点大于等于k的就不用再跳了,显然之前的节点肯定已经大于等于k了. 然后一旦有新的节点等于k就记录一下当前新增加的子串个数. 1 #include<cstdio> 2 #include<cstring> 3 #d

hdu 4436 str2int(后缀自动机)

题目链接:hdu 4436 str2int 题意: 给你n个字符串,每个字符串都是由数字构成,现在让你将这n个字符串所有的不重复子串构成的十进制数字加起来mod2012. 题解: 似乎这种不重复的子串问题,用后缀自动机都比较无脑搞. 首先将所有的串连起来,中间插个特殊字符,然后建立后缀自动机. 然后拓扑排序,从跟开始往下dp. sum[v]=Σ(sum[x]*10+cnt[x]*j),其中cnt[x]表示有多少条路径能到x这个节点,转移为cnt[v]=Σcnt[x] (x能转移到v),j为这个节