zoukankan      html  css  js  c++  java
  • BZOJ.4199.[NOI2015]品酒大会(后缀自动机 树形DP)

    BZOJ
    洛谷

    后缀数组做法
    洛谷上SAM比SA慢...BZOJ SAM却能快近一倍...

    只考虑求极长相同子串,即所有后缀之间的LCP。
    而后缀的LCP在后缀树的LCA处。同差异这道题,在每个点处树形DP统计它作为LCA时的贡献即可(有多少对后缀以它为LCA)。
    而第二问,同样维护子树内的最大值次大值、最小值次小值作为答案即可。

    非后缀节点的(size=0),最值的初值同样要设成(INF)...但是最后也要一样DP。
    初始设成(INF)在最后转移的时候同样要判...(不能是两个(INF)相乘)不妨直接只在(sizegeq2)的时候DFS/更新答案。

    //95648kb	2744ms
    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    #define gc() getchar()
    typedef long long LL;
    const int N=3e5+5,INF=1<<30;
    
    //char OUT[8000000],*O=OUT;//7e6 isn't enough...
    inline int read()
    {
    	int now=0,f=1;register char c=gc();
    	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now*f;
    }
    //inline void print(LL x)
    //{
    //	static char obuf[20];
    //	if(x<0) x=-x, *O++='-';
    //	if(x)
    //	{
    //		int t=0; while(x) obuf[++t]=x%10+48, x/=10;
    //		while(t) *O++=obuf[t--];
    //	}
    //	else *O++='0';
    //}
    
    struct Suffix_Automaton
    {
    	#define S N<<1
    	int las,tot,son[S][26],len[S],fa[S],tm[S],A[S],sz[S],mx1[S],mx2[S],mn1[S],mn2[S];
    	LL sum[N],Ans[N];
    	char s[N];
    	#undef S
    	void Insert(int c,int v)
    	{
    		int p=las,np=++tot;
    		len[las=np]=len[p]+1, sz[np]=1;
    		mx1[np]=mn1[np]=v, mx2[np]=-INF, mn2[np]=INF;
    		for(; p&&!son[p][c]; p=fa[p]) son[p][c]=np;
    		if(!p) fa[np]=1;
    		else
    		{
    			int q=son[p][c];
    			if(len[q]==len[p]+1) fa[np]=q;
    			else
    			{
    				int nq=++tot; len[nq]=len[p]+1;
    				mx1[nq]=mx2[nq]=-INF, mn1[nq]=mn2[nq]=INF;
    				memcpy(son[nq],son[q],sizeof son[q]);
    				fa[nq]=fa[q], fa[q]=fa[np]=nq;
    				for(; son[p][c]==q; p=fa[p]) son[p][c]=nq;
    			}
    		}
    	}
    	void Solve(const int n)
    	{
    		las=tot=1, scanf("%s",s+1);
    		for(int i=1; i<=n; ++i) A[i]=read();
    		for(int i=n; i; --i) Insert(s[i]-'a',A[i]);
    
    		for(int i=1; i<=tot; ++i) ++tm[len[i]];
    		for(int i=1; i<=n; ++i) tm[i]+=tm[i-1];
    		for(int i=tot; i; --i) A[tm[len[i]]--]=i;
    
    		for(int i=tot,v=A[i],x,l; i; v=A[--i])
    		{
    			x=fa[v], l=len[x];
    			sum[l]+=1ll*sz[x]*sz[v], sz[x]+=sz[v];
    			mx1[v]>mx1[x]?(mx2[x]=mx1[x],mx1[x]=mx1[v]):(mx2[x]=std::max(mx2[x],mx1[v]));
    			mx2[x]=std::max(mx2[x],mx2[v]);
    			mn1[v]<mn1[x]?(mn2[x]=mn1[x],mn1[x]=mn1[v]):(mn2[x]=std::min(mn2[x],mn1[v]));
    			mn2[x]=std::min(mn2[x],mn2[v]);
    		}
    		memset(Ans,-0x3f,sizeof Ans);
    		for(int x=1; x<=tot; ++x)
    			sz[x]>=2 && (Ans[len[x]]=std::max(Ans[len[x]],std::max(1ll*mx1[x]*mx2[x],1ll*mn1[x]*mn2[x])));
    
    		for(int i=n-1; ~i; --i) sum[i]+=sum[i+1], Ans[i]=std::max(Ans[i],Ans[i+1]);
    		for(int i=0; i<n; ++i) printf("%lld %lld
    ",sum[i],sum[i]?Ans[i]:0);
    //		for(int i=0; i<n; ++i) print(sum[i]),*O++=' ',print(sum[i]?Ans[i]:0),*O++='
    ';
    //		fwrite(OUT,1,O-OUT,stdout);
    	}
    }sam;
    
    int main()
    {
    	sam.Solve(read());
    	return 0;
    }
    
  • 相关阅读:
    FZU 2112 并查集、欧拉通路
    HDU 5686 斐波那契数列、Java求大数
    Codeforces 675C Money Transfers 思维题
    HDU 5687 字典树插入查找删除
    HDU 1532 最大流模板题
    HDU 5384 字典树、AC自动机
    山科第三届校赛总结
    HDU 2222 AC自动机模板题
    HDU 3911 线段树区间合并、异或取反操作
    CodeForces 615B Longtail Hedgehog
  • 原文地址:https://www.cnblogs.com/SovietPower/p/10235493.html
Copyright © 2011-2022 走看看