其实是练板
hihocoder 1445
求一个串中不同的子串个数,等价于求 ∑l[i]−minlen[i]+1 ∑ l [ i ] − m i n l e n [ i ] + 1
等价于求 ∑l[i]−(l[nxt[i]]+1)+1=∑l[i]−l[nxt[i]] ∑ l [ i ] − ( l [ n x t [ i ] ] + 1 ) + 1 = ∑ l [ i ] − l [ n x t [ i ] ]
然后建后缀自动机就好了。
代码:
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 2000005
using namespace std;
typedef long long LL;
int lt,nd,to[N][26],nxt[N],l[N],a[N],b[N];
char s[N];
inline void nsrt(int c){
int p=lt,x=++nd,q; lt=x,l[x]=l[p]+1;
while (p&&!to[p][c]) to[p][c]=x,p=nxt[p];
if (!p) nxt[x]=1;
else
if (l[q=to[p][c]]==l[p]+1) nxt[x]=q;
else{
int y=++nd; l[y]=l[p]+1;
memcpy(to[y],to[q],sizeof(to[q]));
nxt[y]=nxt[q],nxt[q]=nxt[x]=y;
while (to[p][c]==q) to[p][c]=y,p=nxt[p];
}
}
int main(){
scanf("%s",s+1); LL ans=0; lt=nd=1;
for (int i=1;s[i];i++) nsrt(s[i]-'a');
for (int i=1;i<=nd;i++)
ans+=(LL)(l[i]-l[nxt[i]]);
printf("%lld\n",ans);
}
hihocoder 1449
其实就是求长度为k的子串的|endpos|的最大值。
∵endpos(x)⫋endpos(nxt[x])
∵
e
n
d
p
o
s
(
x
)
⫋
e
n
d
p
o
s
(
n
x
t
[
x
]
)
∴|endpos(x)|=∑nxt[i]=x|endpos(i)|
∴
|
e
n
d
p
o
s
(
x
)
|
=
∑
n
x
t
[
i
]
=
x
|
e
n
d
p
o
s
(
i
)
|
当
x
x
包含的某个前缀时
|endpos(x)|
|
e
n
d
p
o
s
(
x
)
|
要+1。
建好自动机后拓排一遍求累加就好了。
如果直接更新ans[i]会T,因为endpos(x)要更新
l[nxt[x]]+1
l
[
n
x
t
[
x
]
]
+
1
到
l[x]
l
[
x
]
的答案。
考虑到ans[]递减,而且连续一段的贡献相等,那么每次只要更新
l[x]
l
[
x
]
即可,然后倒着更新
ans[i]=max(ans[i],ans[i+1])
a
n
s
[
i
]
=
m
a
x
(
a
n
s
[
i
]
,
a
n
s
[
i
+
1
]
)
。
这道题如果没有提示我估计会T
代码:
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 2000005
#define F inline
using namespace std;
int n,lt,nd,to[N][26],nxt[N],l[N],sum[N];
int ans[N],in[N],que[N];
char s[N]; bool f[N];
F void nsrt(int c){
int p=lt,x=++nd,q; f[lt=x]=l[x]=l[p]+1;
while (p&&!to[p][c]) to[p][c]=x,p=nxt[p];
if (!p) nxt[x]=1;
else
if (l[q=to[p][c]]==l[p]+1) nxt[x]=q;
else{
int y=++nd; l[y]=l[p]+1;
memcpy(to[y],to[q],sizeof(to[q]));
nxt[y]=nxt[q],nxt[q]=nxt[x]=y;
while (to[p][c]==q) to[p][c]=y,p=nxt[p];
}
}
F void writec(int x){ if (x>9) writec(x/10); putchar(x%10+48); }
F void _write(int x){ writec(x),putchar('\n'); }
F void tp(){
int r=0,w=1;
for (int i=1;i<=nd;i++) in[nxt[i]]++;
for (int i=1;i<=nd;i++) if (!in[i]) que[++w]=i;
for (int i=1;i<=nd;i++) sum[i]+=f[i];
while (r<w){
int x=que[++r];
if (!(--in[nxt[x]])) que[++w]=nxt[x];
sum[nxt[x]]+=sum[x];
}
}
int main(){
scanf("%s",s+1),lt=nd=1,n=strlen(s+1);
for (int i=1;s[i];i++) nsrt(s[i]-'a'); tp();
for (int i=1;i<=nd;i++) ans[l[i]]=max(ans[l[i]],sum[i]);
for (int i=n-1;i;i--) ans[i]=max(ans[i],ans[i+1]);
for (int i=1;i<=n;i++) _write(ans[i]);
return 0;
}