BZOJ 4516 [Sdoi2016] 生成魔咒
传送门
心态崩了++
后缀自动机板子题[考场上要是不会后缀自动机就崩了T^T]
可以看出 每次答案的贡献就是和原来本质不同的子串数量
根据SPOJ7258我们可以得到 本质不同的子串数量可以通过建出自动机 树形dp解决
我们需要知道的就是 连向它的那个链
就是我们建立自动机的时候的那个找的p
直接求一下就好了
另外的理解方式就是我们要求本质不同的前缀数量 那么就是parent树上len的定义 直接len[x]-len[fa]就是答案
时间复杂度O(n)
写完了调过样例交了一发WA 然后看到STD里开longlong了改了一发longlong又一发WA 然后心态崩掉 一点一点重推 最后发现 我输出没改 还是%d [手动再见]
附代码。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#define inf 20021225
#define ll long long
#define mxn 100010
using namespace std;
struct node{int fa,len;map<int,int> ch;}t[mxn*4];
int poi,lt,rt,n;ll ans;
void insert(int c)
{
int p=lt,np=lt=++poi; t[np].len=t[p].len+1;
for(;p&&!t[p].ch[c];p=t[p].fa) t[p].ch[c]=np;
ans+=t[np].len;
if(!p){t[np].fa=rt;return;}
int q=t[p].ch[c];
if(t[q].len==t[p].len+1){ans-=t[q].len;t[np].fa=q;return;}
int nq=++poi; t[nq].len=t[p].len+1;
t[nq].ch=t[q].ch; ans-=t[nq].len;
t[nq].fa=t[q].fa; t[q].fa=t[np].fa=nq;
for(;p&&t[p].ch[c]==q;p=t[p].fa) t[p].ch[c]=nq;
}
int main()
{
int x;
scanf("%d",&n);
lt=rt=++poi;
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
insert(x);
printf("%lld\n",ans);
}
return 0;
}
本题还有一个非常优秀的做法就是SA
我们发现 要求本质不同的前缀数量 那么就是 len - max_lcp 我们发现 这个不就是SA的height吗!
我们可以通过倒过来删除的操作 链表维护一通 也是可以AC的~
时间复杂度是O(nlgn) 瓶颈在于求SA 如果你是大佬写DC3的话请无视
我这辈子也不可能写DC3的[Flag]