bzoj4199 [Noi2015]品酒大会
题面:见uoj
正解:后缀自动机+后缀树+树形$dp$。
好像这题正解是后缀数组来着,然而用后缀自动机就简单多了。。
反串构出后缀树,然后直接树形$dp$即可,注意最大答案可能是最小值与最小值的乘积。
1 #include <bits/stdc++.h> 2 #define il inline 3 #define RG register 4 #define ll long long 5 #define Inf (1000000007) 6 #define inf (1LL<<60) 7 #define N (600010) 8 9 using namespace std; 10 11 struct edge{ int nt,to; }g[N<<1]; 12 13 int ch[N][26],fa[N],l[N],sz[N],Mx[N],Mn[N],val[N],head[N],a[N],n,la,tot,len,num; 14 ll sum[N],res[N]; 15 char s[N]; 16 17 il int gi(){ 18 RG int x=0,q=1; RG char ch=getchar(); 19 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 20 if (ch=='-') q=-1,ch=getchar(); 21 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 22 return q*x; 23 } 24 25 il void insert(RG int from,RG int to){ 26 g[++num]=(edge){head[from],to},head[from]=num; return; 27 } 28 29 il void add(RG int c){ 30 RG int p=la,np=++tot; la=np,l[np]=l[p]+1,sz[np]=1; 31 for (;p && !ch[p][c];p=fa[p]) ch[p][c]=np; 32 if (!p){ fa[np]=1; return; } RG int q=ch[p][c]; 33 if (l[q]==l[p]+1) fa[np]=q; else{ 34 RG int nq=++tot; l[nq]=l[p]+1,val[nq]=-Inf; 35 fa[nq]=fa[q],fa[q]=fa[np]=nq; 36 memcpy(ch[nq],ch[q],sizeof(ch[q])); 37 for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq; 38 } 39 return; 40 } 41 42 il void dfs(RG int x){ 43 Mx[x]=Mn[x]=val[x]; 44 for (RG int i=head[x],v;i;i=g[i].nt){ 45 v=g[i].to,dfs(v),sum[l[x]]+=1LL*sz[x]*sz[v],sz[x]+=sz[v]; 46 if (Mx[x]!=-Inf && Mx[v]!=-Inf) res[l[x]]=max(res[l[x]],1LL*Mx[x]*Mx[v]); 47 if (Mn[x]!=-Inf && Mn[v]!=-Inf) res[l[x]]=max(res[l[x]],1LL*Mn[x]*Mn[v]); 48 Mx[x]=max(Mx[x],Mx[v]),Mn[x]=min(Mn[x],Mn[v]); if (Mn[x]==-Inf) Mn[x]=Mn[v]; 49 } 50 return; 51 } 52 53 int main(){ 54 #ifndef ONLINE_JUDGE 55 freopen("savour.in","r",stdin); 56 freopen("savour.out","w",stdout); 57 #endif 58 n=gi(),scanf("%s",s+1),len=strlen(s+1),val[la=++tot]=-Inf; 59 for (RG int i=1;i<=n;++i) a[i]=gi(),res[i]=-inf; res[0]=-inf; 60 for (RG int i=len;i;--i) add(s[i]-'a'),val[la]=a[i]; 61 for (RG int i=2;i<=tot;++i) insert(fa[i],i); dfs(1); 62 for (RG int i=n-1;i>=0;--i) sum[i]+=sum[i+1],res[i]=max(res[i],res[i+1]); 63 for (RG int i=0;i<n;++i) printf("%lld %lld\n",sum[i],sum[i] ? res[i] : 0); 64 return 0; 65 }