不懂线性构造后缀树的看这里:http://blog.csdn.net/guoshiyuan484/article/details/73658551
这个题主要就是注意他计算的是后缀,所以我们让后缀自动机主干上的点的size=1因为不管你怎么构造后缀自动机,在从原点一直连续转移到结尾点的路径上,每个点的最长串一定都是一个后缀(当然我说的是让原来的字符串反转后构造出来的自动机!)
其他就是dp的时候有一些技巧注意,具体看代码,哦还有注意用long long
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<string.h>
using namespace std;
struct treee
{
int fa,nextt[29];
long long max,size;
};
treee tree[2000000];
vector<int>to[2000000];
int tot = 2;
char s[600000];
void construct(char *s,int len)
{
int last = 1; tree[1].max = 0;
for (int i = len-1; i>=0; i--)
{
int temp = s[i] - 'a'; int now = tot;
tree[now].max = tree[last].max + 1; tree[tot].size = 1; int tempfa = last; last = now;
while (tempfa&&tree[tempfa].nextt[temp] == 0)tree[tempfa].nextt[temp] = now,tempfa=tree[tempfa].fa;
if (!tempfa)
{
tree[now].fa = 1;
}
else
{
int link = tree[tempfa].nextt[temp];
if (tree[link].max == tree[tempfa].max + 1)tree[now].fa = link;
else
{
int neww = ++tot; tree[neww] = tree[link]; tree[neww].size = 0; tree[neww].max = tree[tempfa].max + 1;
tree[now].fa = neww; tree[link].fa = neww;
while (tempfa&&tree[tempfa].nextt[temp] == link)tree[tempfa].nextt[temp] = neww, tempfa = tree[tempfa].fa;//由于头结点是空的,所以对于这道题而言该不该都是无所谓的。
}
}
tot++;
}
for (int i = tot - 1; i > 1; i--)to[tree[i].fa].push_back(i);
}
long long dfs(int num,long long &ans)
{
for (int i = 0; i < to[num].size(); i++)
{
int kk = to[num][i];
tree[num].size += dfs(kk, ans);
}
ans += tree[num].size*(tree[num].size - 1)*(tree[num].max-tree[tree[num].fa].max);
return tree[num].size;
}
int main()
{
scanf("%s", s);
long long n = strlen(s);
long long ans=0;
//long long n = 500000;
construct(s, n);
dfs(1, ans);
long long all = n*(n - 1)*(n + 1) / 2;
all -= ans;
printf("%lld\n",all);
return 0;
}
为了好复制:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<string.h>
using namespace std;
struct treee
{
int fa,nextt[29];
long long max,size;
};
treee tree[2000000];
vector<int>to[2000000];
int tot = 2;
char s[600000];
void construct(char *s,int len)
{
int last = 1; tree[1].max = 0;
for (int i = len-1; i>=0; i--)
{
int temp = s[i] - 'a'; int now = tot;
tree[now].max = tree[last].max + 1; tree[tot].size = 1; int tempfa = last; last = now;
while (tempfa&&tree[tempfa].nextt[temp] == 0)tree[tempfa].nextt[temp] = now,tempfa=tree[tempfa].fa;
if (!tempfa)
{
tree[now].fa = 1;
}
else
{
int link = tree[tempfa].nextt[temp];
if (tree[link].max == tree[tempfa].max + 1)tree[now].fa = link;
else
{
int neww = ++tot; tree[neww] = tree[link]; tree[neww].size = 0; tree[neww].max = tree[tempfa].max + 1;
tree[now].fa = neww; tree[link].fa = neww;
while (tempfa&&tree[tempfa].nextt[temp] == link)tree[tempfa].nextt[temp] = neww, tempfa = tree[tempfa].fa;//由于头结点是空的,所以对于这道题而言该不该都是无所谓的。
}
}
tot++;
}
for (int i = tot - 1; i > 1; i--)to[tree[i].fa].push_back(i);
}
long long dfs(int num,long long &ans)
{
for (int i = 0; i < to[num].size(); i++)
{
int kk = to[num][i];
tree[num].size += dfs(kk, ans);
}
ans += tree[num].size*(tree[num].size - 1)*(tree[num].max-tree[tree[num].fa].max);
return tree[num].size;
}
int main()
{
scanf("%s", s);
long long n = strlen(s);
long long ans=0;
//long long n = 500000;
construct(s, n);
dfs(1, ans);
long long all = n*(n - 1)*(n + 1) / 2;
all -= ans;
printf("%lld\n",all);
return 0;
}