BZOJ
洛谷
后綴數組做法。
洛谷上SAM比SA慢...BZOJ SAM卻能快近一倍...
只考慮求極長相同子串,即所有后綴之間的LCP。
而后綴的LCP在后綴樹的LCA處。同差異這道題,在每個點處樹形DP統計它作為LCA時的貢獻即可(有多少對后綴以它為LCA)。
而第二問,同樣維護子樹內的最大值次大值、最小值次小值作為答案即可。
非后綴節點的\(size=0\),最值的初值同樣要設成\(INF\)...但是最后也要一樣DP。
初始設成\(INF\)在最后轉移的時候同樣要判...(不能是兩個\(INF\)相乘)不妨直接只在\(size\geq2\)的時候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<<1int 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 Svoid 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\n",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++='\n';
// fwrite(OUT,1,O-OUT,stdout);}
}sam;int main()
{sam.Solve(read());return 0;
}
轉載于:https://www.cnblogs.com/SovietPower/p/10235493.html
總結
以上是生活随笔為你收集整理的BZOJ.4199.[NOI2015]品酒大会(后缀自动机 树形DP)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。