SP8222 NSUBSTR - Substrings
题面传送门
感觉统计答案那一步很妙啊。
其实对于每个节点代表的字符串集合的出现次数很容易统计。
但是我们发现一个节点所代表的其实是一组字符串,而这个东西看上去只能线段树覆盖,时间复杂度是\(O(nlogn)\)的。
然而spoj死慢的机子紧张的时限使得这个不怎么容易通过。
然而我们发现这个答案具有单调性,就是\(f(x)\leq f(x+1)\)
所以把后面的值前缀最大值到前面去是没有影响的。
时间复杂度就可以\(O(n)\)了。
code:
#include<cstdio>
#include<cstring>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define beg(x) int cur=s.h[x]
#define end cur
#define go cur=tmp.z
#define l(x) x<<1
#define r(x) x<<1|1
#define N 500039
#define ll long long
#define ui unsigned int
using namespace std;
int n,m,k,x,y,z;char s[N];
struct SAM{
int fa[N],len[N],son[N][26],siz[N],cnt=1,last=1,p,cur,pus,now,f[N],g[N],a[N];
I void insert(int x){
p=last;now=last=++cnt;len[now]=len[p]+1;siz[now]++;
while(p&&!son[p][x]) son[p][x]=now,p=fa[p];
if(!p) return (void)(fa[now]=1);
cur=son[p][x];if(len[cur]==len[p]+1) fa[now]=cur;
else{
fa[pus=++cnt]=fa[cur];len[pus]=len[p]+1;memcpy(son[pus],son[cur],sizeof(son[pus]));fa[cur]=fa[now]=pus;
while(p&&son[p][x]==cur) son[p][x]=pus,p=fa[p];
}
}
I void solve(){
register int i;
for(i=1;i<=cnt;i++) g[len[i]]++;
for(i=1;i<=cnt;i++) g[i]+=g[i-1];
for(i=1;i<=cnt;i++) a[g[len[i]]--]=i;
for(i=cnt;i;i--) f[len[a[i]]]=max(siz[a[i]],f[len[a[i]]]),siz[fa[a[i]]]+=siz[a[i]];
for(i=n;i;i--) f[i]=max(f[i],f[i+1]);
}
}g;
int main(){
freopen("1.in","r",stdin);
register int i;
scanf("%s",s+1);n=strlen(s+1);
for(i=1;i<=n;i++) g.insert(s[i]-'a');g.solve();
for(i=1;i<=n;i++) printf("%d\n",g.f[i]);
}