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]

posted @ 2018-12-18 15:36  寒雨微凝  阅读(83)  评论(0编辑  收藏  举报