以此纪念我都快忘了的后缀自动机(捂脸)

不过这题有两种做法:

用后缀自动机,先把原串再接遍中间加入特殊连接字符再把原串反接两遍,对这个新构造出的串做后缀自动机。(或者直接建立广义后缀自动机)

下面只要统计长度小于等于 n 的串即可。这可以从 parent 树即后缀树来考虑,注意到每个节点可以接收的子串长度为[mxlen[fa[x]]+1,mxlen[x]]

只要对这个长度区间对n取min再统计即可

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 typedef long long ll;
 5 int fa[400010],go[400010][26],mx[400010],n,t,last;
 6 char a[50010];
 7 void add(int c)
 8 {
 9     int np,nq,q,p=last;
10     if (!go[last][c])
11     {
12         np=++t;
13         mx[np]=mx[p]+1;
14         for (;p&&!go[p][c]; p=fa[p]) go[p][c]=np;
15     }
16     else np=0;
17     if (!p) fa[np]=1;
18     else {
19         q=go[p][c];
20         if (mx[q]==mx[p]+1) fa[np]=q;
21         else {
22             nq=++t;
23             mx[nq]=mx[p]+1;
24             memcpy(go[nq],go[q],sizeof(go[q]));
25             fa[nq]=fa[q]; fa[q]=fa[np]=nq;
26             for (;go[p][c]==q; p=fa[p]) go[p][c]=nq;
27         }
28     }
29     last=go[last][c];
30 }
31 
32 int main()
33 {
34     scanf("%d",&n);
35     scanf("%s",a+1);
36     last=t=1;
37     for (int i=1; i<=n; i++)
38         add(a[i]-'a');
39     for (int i=1; i<=n; i++)
40         add(a[i]-'a');
41     last=1;
42     for (int i=n; i; i--)
43         add(a[i]-'a');
44     for (int i=n; i; i--)
45         add(a[i]-'a');
46     ll ans=0;
47     for (int i=2; i<=t; i++)
48         ans+=min(n,mx[i])-min(mx[fa[i]],n);
49     printf("%lld\n",ans);
50 }
自动机

另一种诡异的做法:由于数据随机,那么当串长足够大时很大概率都是互不相同的,干脆就直接认为全不相同

因此只要找小串长的不同种类即可,这就直接用 hash

暴力判断即可。

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 typedef long long ll;
 5 char a[50010];
 6 set<ll> f[20];
 7 int n;
 8 using namespace std;
 9 typedef long long ll;
10 const int mx=15;
11 int main()
12 {
13     scanf("%d",&n);
14     scanf("%s",a);
15     for (int i=0; i<n; i++)
16     {
17         ll h1=0,h2=0;
18         for (int l=0; l<min(n,mx); l++)
19         {
20             h1=h1*26+a[(i+l)%n]-'a';
21             h2=h2*26+a[(i-l+n)%n]-'a';
22             f[l].insert(h1);
23             f[l].insert(h2);
24         }
25     }
26     ll ans=2ll*n*max(0,n-mx);
27     for (int l=0; l<mx; l++)
28         ans+=f[l].size();
29     printf("%lld\n",ans);
30 }
View Code
posted on 2017-07-19 16:48  acphile  阅读(205)  评论(0编辑  收藏  举报