codeforces 123D. String(后缀自动机)
题目链接:http://codeforces.com/problemset/problem/123/D
题意:
如果字符串y在字符串x中出现n次,那么F(x,y)=n*(n+1)/2
现在给一个字符串,求所有的F(s,x)的和,x为字符串的所有不相同的子串.
思路:
这道题可以考虑用后缀数组做,麻烦一点:codeforces-123D-解题报告(SA)
直接SAM
right[v]就是SAM上状态表示的所有字符串出现的次数。
那么每个状态的答案就是right[v](right[v]+1)/2(st[v].len-st[st[v].link].len)
累加即可。
1/* ***********************************************
2Author :111qqz
3Created Time :2017年11月08日 星期三 18时50分18秒
4File Name :3518.cpp
5************************************************ */
6
7//#include <bits/stdc++.h>
8#include <cstring>
9#include <string>
10#include <algorithm>
11#include <iostream>
12#include <cstdio>
13#include <cmath>
14#define PB push_back
15#define fst first
16#define sec second
17#define lson l,m,rt<<1
18#define rson m+1,r,rt<<1|1
19#define ms(a,x) memset(a,x,sizeof(a))
20typedef long long LL;
21#define pi pair < int ,int >
22#define MP make_pair
23
24using namespace std;
25const double eps = 1E-8;
26const int dx4[4]={1,0,0,-1};
27const int dy4[4]={0,-1,1,0};
28const int inf = 0x3f3f3f3f;
29#define MAXALP 55 //还有大写字母orz
30int k;
31struct state
32{
33 int len, link, nxt[MAXALP];
34};
35const int N =1E5+7;
36state st[N*2];
37int sz, last,rt;
38char s[N];
39int Right[2*N];
40int cnt[2*N],rk[2*N];//for radix sort
41int dp[2*N],lazy[2*N];
42void sa_init()
43{
44 sz = 0;
45 last = rt = ++sz;
46 st[1].len = 0;
47 st[1].link=-1;
48 ms(st[1].nxt,-1);
49}
50void sa_extend(int c)
51{
52 int cur = ++sz;
53 st[cur].len = st[last].len + 1;
54 memset(st[cur].nxt, -1, sizeof(st[cur].nxt));
55 int p;
56 for (p = last; p != -1 && st[p].nxt[c] == -1; p = st[p].link)
57 st[p].nxt[c] = cur;
58 if (p == -1) {
59 st[cur].link = rt;
60 } else {
61 int q = st[p].nxt[c];
62 if (st[p].len + 1 == st[q].len) {
63 st[cur].link = q;
64 } else {
65 int clone = ++sz ;
66 st[clone].len = st[p].len + 1;
67 st[clone].link = st[q].link;
68 memcpy(st[clone].nxt, st[q].nxt, sizeof(st[q].nxt));
69 for (; p != -1 && st[p].nxt[c] == q; p = st[p].link)
70 st[p].nxt[c] = clone;
71 st[q].link = st[cur].link = clone;
72 }
73 }
74 last = cur;
75}
76void topo()
77{
78 ms(cnt,0);
79 for (int i = 1 ; i <= sz ; i++) cnt[st[i].len]++;
80 for ( int i = 1 ; i <= sz ; i++) cnt[i]+=cnt[i-1];
81 for (int i = 1 ; i <= sz ;i++) rk[cnt[st[i].len]--] = i;
82}
83char ST[N];
84int idx( char c)
85{
86 if (c>='a'&&c<='z') return c-'a';
87 return c-'A'+26;
88}
89int main()
90{
91#ifndef ONLINE_JUDGE
92 freopen("./in.txt","r",stdin);
93#endif
94 ms(Right,0);
95 ms(lazy,0); //parent树上的lazy标记,最后子底向上更新
96 scanf("%s",ST);
97// cout<<"ST:"<<ST<<endl;
98 sa_init();
99 for (int i = 0,len = strlen(ST); i < len ; i++)
100 {
101 Right[sz+1] = 1;
102 sa_extend(idx(ST[i]));
103 }
104 topo();
105 for ( int i = sz ; i >=1 ; i--) if (st[rk[i]].link!=-1)Right[st[rk[i]].link]+=Right[rk[i]];
106
107 LL ans = 0 ;
108 for ( int i = sz ; i >= 1 ; i--)
109 {
110 int v = rk[i];
111 ans = ans + 1LL*Right[v]*(Right[v]+1)/2*(st[v].len-st[st[v].link].len);
112 printf("ans:%lld\n",ans);
113 }
114 printf("%lld\n",ans);
115
116#ifndef ONLINE_JUDGE
117 fclose(stdin);
118#endif
119 return 0;
120}
121
122
123
124
125
126
127
128
129
130/* ***********************************************
131Author :111qqz
132Created Time :2017年11月15日 星期三 19时06分15秒
133File Name :SAM.cpp
134************************************************ */
135
136#include <bits/stdc++.h>
137#define PB push_back
138#define fst first
139#define sec second
140#define lson l,m,rt<<1
141#define rson m+1,r,rt<<1|1
142#define ms(a,x) memset(a,x,sizeof(a))
143typedef long long LL;
144#define pi pair < int ,int >
145#define MP make_pair
146
147using namespace std;
148const double eps = 1E-8;
149const int dx4[4]={1,0,0,-1};
150const int dy4[4]={0,-1,1,0};
151const int inf = 0x3f3f3f3f;
152const int N=5E5+7;
153struct SAM
154{
155 #define MAXALP 30
156 struct state
157 {
158 int len, link, nxt[MAXALP];
159 int leftmost; //某个状态的right集合中r值最小的
160 int rightmost;//某个状态的right集合的r的最大值
161 int Right; //right集合大小
162 };
163 state st[N*2];
164 char S[N];
165 int sz, last,rt;
166 char s[N];
167 int cnt[2*N],rk[2*N];//for radix sort
168 int idx(char c)
169 {
170 if (c>='a'&&c<='z') return c-'a';
171 return c-'A'+26;
172 }
173 void init()
174 {
175 sz = 0;
176 ms(st,0);
177 last = rt = ++sz;
178 st[1].len = 0;
179 st[1].link=-1;
180 st[1].rightmost=0;
181 ms(st[1].nxt,-1);
182 }
183 void extend(int c,int head)
184 {
185 int cur = ++sz;
186 st[cur].len = st[last].len + 1;
187 st[cur].leftmost = st[cur].rightmost = head;
188 memset(st[cur].nxt, -1, sizeof(st[cur].nxt));
189 int p;
190 for (p = last; p != -1 && st[p].nxt[c] == -1; p = st[p].link)
191 st[p].nxt[c] = cur;
192 if (p == -1) {
193 st[cur].link = rt;
194 } else {
195 int q = st[p].nxt[c];
196 if (st[p].len + 1 == st[q].len) {
197
198 st[cur].link = q;
199 } else {
200 int clone = ++sz ;
201 st[clone].len = st[p].len + 1;
202 st[clone].link = st[q].link;
203 memcpy(st[clone].nxt, st[q].nxt, sizeof(st[q].nxt));
204 st[clone].leftmost = st[q].leftmost;
205 st[clone].rightmost = st[q].rightmost;
206 for (; p != -1 && st[p].nxt[c] == q; p = st[p].link)
207 st[p].nxt[c] = clone;
208 st[q].link = st[cur].link = clone;
209 }
210 }
211 last = cur;
212 }
213 void build ()
214 {
215 init();
216 for ( int i = 0,_len = strlen(S) ; i < _len ; i++)
217 {
218 st[sz+1].Right = 1;
219 extend(idx(S[i]),i);
220 }
221 }
222 void topo()
223 {
224 ms(cnt,0);
225 for (int i = 1 ; i <= sz ; i++) cnt[st[i].len]++;
226 for ( int i = 1 ; i <= sz ; i++) cnt[i]+=cnt[i-1];
227 //rk[1]是len最小的状态的标号
228 for (int i = 1 ; i <= sz ;i++) rk[cnt[st[i].len]--] = i;
229 }
230 void pre() //跑拓扑序,预处理一些东西
231 {
232 for ( int i = sz ; i >= 2 ; i--)
233 {
234 int v = rk[i];
235 int fa = st[v].link;
236 if (fa==-1) continue;
237 st[fa].rightmost = max(st[fa].rightmost,st[v].rightmost);
238 st[fa].Right += st[v].Right;
239 }
240 }
241 void solve()
242 {
243
244 LL ans = 0 ;
245 for ( int i = sz ; i >= 2 ; i--)
246 {
247 int v = rk[i];
248 if (st[v].link==-1) continue;
249 ans = ans + 1LL * st[v].Right*(st[v].Right+1)/2 * (st[v].len-st[st[v].link].len);
250 }
251 printf("%lld\n",ans);
252 }
253 int LCS(char *s)
254 {
255 int ans = 0,len = 0 ;
256 int p = rt;
257 for ( int i = 0 ,_len = strlen(s) ; i < _len ; i++)
258 {
259 int ID = s[i]-'a';
260 if (st[p].nxt[ID]!=-1) p = st[p].nxt[ID],len++;
261 else
262 {
263 while (p!=-1&&st[p].nxt[ID]==-1) p = st[p].link;
264 if (p==-1) p=rt,len=0;else len = st[p].len+1,p = st[p].nxt[ID];
265 }
266 // printf("len:%d\n",len);
267 ans = max(ans,len);
268 }
269 return ans;
270 }
271}A;
272char B[N];
273int main()
274{
275#ifndef ONLINE_JUDGE
276 freopen("./in.txt","r",stdin);
277#endif
278 scanf("%s",A.S);
279 A.build();
280 A.topo();
281 A.pre();
282 A.solve();
283
284#ifndef ONLINE_JUDGE
285 fclose(stdin);
286#endif
287 return 0;
288}