[HAOI2016]找相同字符(SAM)
Posted zhangbuang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HAOI2016]找相同字符(SAM)相关的知识,希望对你有一定的参考价值。
题目描述
给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数。两个方案不同当且仅当这两个子串中有一个位置不同。
输入输出格式
输入格式:两行,两个字符串s1,s2,长度分别为n1,n2。1 <=n1, n2<= 200000,字符串中只有小写字母
输出格式:输出一个整数表示答案
输入输出样例
输入样例#1:
复制
aabb
bbaa
输出样例#1: 复制
10
这到题目是vj上一道题目的简化版
对第一个串建立自动机 在拓扑一边球每个状态串的出现次数
然后然第二个串在树上跑
记录一下当强匹配的长度,假设到达状态P,状态P中的小于匹配长的串都符合,(注意不是P中的所有串),
然后就是P的所有的fa都符合,为了避免总是向上找fa而TLE,所以打一个lz标记,最后的时候一边拓扑统计剩下的答案:
1 #include<iostream>
2 #include<cstdio>
3 #include<queue>
4 #include<map>
5 #include<set>
6 #include<queue>
7 #include<algorithm>
8 #include<cmath>
9 #include<stack>
10 #include<cstring>
11 #define mem(a,b) memset(a,b,sizeof a)
12 #define sc(a) scanf("%d",&(a))
13 #define scc(a,b) scanf("%d %d",&(a),&(b))
14 #define ll long long
15 using namespace std;
16
17
18 int kd[1000000];
19 const int N = 200010;
20
21 struct dd
22 {
23
24 int fa,len;
25 int ch[29];
26
27 } dian[1200000];
28
29 int cnt[1200000];
30 ll num[N<<1];
31 int last=1;
32 int tot=1;
33 inline void add(int c)
34
35 {
36 int p=last;
37 int np=last=++tot;
38 dian[np].len=dian[p].len+1;
39 num[np] = 1;
40 for(; p&&!dian[p].ch[c]; p=dian[p].fa)dian[p].ch[c]=np;
41 if(!p)dian[np].fa=1,cnt[1]++;
42 else
43 {
44 int q=dian[p].ch[c];
45 if(dian[q].len==dian[p].len+1)dian[np].fa=q,cnt[q]++;
46 else
47 {
48 int nq=++tot;
49 dian[nq]=dian[q];
50 dian[nq].len=dian[p].len+1;
51 num[nq]=0;
52 dian[q].fa=dian[np].fa=nq;
53 cnt[nq]+=2;
54 for(; p&&dian[p].ch[c]==q; p=dian[p].fa)dian[p].ch[c]=nq;
55
56 }
57 }
58 }
59 int ans=0;
60 vector<int > v;
61 void top()
62 {
63 queue<int >q;
64 for(int i=2; i<=tot; i++)if(!cnt[i])q.push(i);
65 while(!q.empty())
66 {
67
68 int t=q.front(); v.push_back(t);
69 q.pop();
70 num[dian[t].fa] += num[t];
71 if(--cnt[dian[t].fa] == 0) q.push(dian[t].fa);
72 }
73
74 }
75 ll lz[N<<1];
76
77 void work(string s,int len)
78 {
79 ll ans=0;
80 int now = 1; int tt=0;
81 for(int i=0; i<len; i++)
82 {
83 int so=s[i]-‘a‘;
84 if(dian[now].ch[so])
85 {
86 now=dian[now].ch[so]; tt++;
87 //ans += 1ll*num[now]*(dian[now].len - dian[dian[now].fa].len);
88 // lz[dian[now].fa] += 1;
89 }
90 else
91 {
92 while(now&&!dian[now].ch[so])now=dian[now].fa,tt=dian[now].len;
93 if(!now)now=1,tt=0;
94 else
95 {
96 now=dian[now].ch[so]; tt++;
97 // ans += 1ll*num[now]*(dian[now].len - dian[dian[now].fa].len);
98 // lz[dian[now].fa] += 1;
99 }
100 }
101 if(now!=1)
102 {
103 ans += 1ll*num[now]*(tt- dian[dian[now].fa].len);
104 lz[dian[now].fa] += 1;
105 }
106
107 // cout<<"HERE: "<<now<<" "<<ans<<endl;
108 }
109 // cout<<"NOW: "<<ans<<endl;
110 int sze=v.size();
111 for(int i=0; i<sze; i++)
112 {
113 int t=v[i];
114
115 ans += 1ll*lz[t]*num[t]*(dian[t].len - dian[dian[t].fa].len);
116 lz[dian[t].fa] += lz[t];
117 lz[t]=0;
118 }
119
120 cout<<ans;
121
122
123
124
125 }
126 signed main()
127 {
128 string s;
129 cin>>s;
130 int len = s.length();
131 for(int i=0; i<len; i++)add(s[i]-‘a‘);
132 cin>>s;
133 top();
134 //cout<<"TOT: "<<tot<<endl;
135 // for(int i=1;i<=tot;i++)cout<<num[i]<<" ";
136 // cout<<endl;
137
138 work(s,s.length());
139
140
141 }
以上是关于[HAOI2016]找相同字符(SAM)的主要内容,如果未能解决你的问题,请参考以下文章