[NOI2015]品酒大会

题意

i[0,n) ∀ i ∈ [ 0 , n ) 求有多少对后缀满足 Len(lcp)i L e n ( l c p ) ≥ i ,以及满足条件的两个后缀的权值乘积的最大值


题解

大于等于可以变成求 Len(lcp)=i L e n ( l c p ) = i ,然后求一遍后缀和,后缀最大值即可

考虑 Len(lcp) L e n ( l c p ) 就是这两个后缀在后缀树上的 lca l c a 深度

那么就可以建出后缀树,对于每一个节点 DP D P 一下, DP D P 方法和差异一样差异这道题真是一道好模板啊

至于最大值,因为有负数,就要记录一下当前子树里的最大最小值和次大次小值,然后对于当前节点所对于深度的答案转移就好了

当然,如果这颗子树里后缀节点数目 <2 < 2 时,是可以直接退掉的

#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
template<class T>inline void sd(T&x){
    char c;T y=1;while(c=gc(),(c<48||57<c)&&c!=-1)if(c==45)y=-1;x=c-48;
    while(c=gc(),47<c&&c<58)x=x*10+c-48;x*=y;
}
inline void gs(char*s){char c;while(c=gc(),c<32);*s++=c;while(c=gc(),c>32)*s++=c;}
char sr[1<<21],z[20];int C=-1,Z;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
template<class T>inline void we(T x){
    if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]=' ';
}
const int N=3e5+5,M=2*N,inf=1e9+7;
typedef long long ll;
typedef int arr[M];
int n,w[N];char s[N];
struct SAM{
    int las,T,ch[M][26];arr fa,len,sz;
    SAM(){las=T=1;}
    inline void ins(int c,int w){
        int p=las,np;fa[np=las=++T]=1,len[np]=len[p]+1;
        for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
        mx[T]=mi[T]=w,mx2[T]=-inf,mi2[T]=inf,sz[T]=1;
        if(p){
            int q=ch[p][c],nq;
            if(len[p]+1==len[q])fa[np]=q;
            else{
                nq=++T;mx[T]=mx2[T]=-inf,mi[T]=mi2[T]=inf;
                fa[nq]=fa[q],len[nq]=len[p]+1,memcpy(ch[nq],ch[q],4*26);
                for(fa[np]=fa[q]=nq;ch[p][c]==q;p=fa[p])ch[p][c]=nq;
            }
        }
    }
    struct eg{int nx,to;}e[M];
    int ce;arr fi,mx,mx2,mi,mi2,sx;ll sum[M],ans[M];
    inline void add(int u,int v){e[++ce]=(eg){fi[u],v},fi[u]=ce;}
    inline void ck1(int u,int w){if(w>mx[u])mx2[u]=mx[u],mx[u]=w;else if(w>mx2[u])mx2[u]=w;}
    inline void ck2(int u,int w){if(w<mi[u])mi2[u]=mi[u],mi[u]=w;else if(w<mi2[u])mi2[u]=w;}
    void dfs(int u){
        int siz=0;
        go(u){
            dfs(v);siz+=sz[v];
            ck1(u,mx[v]),ck1(u,mx2[v]);
            ck2(u,mi[v]),ck2(u,mi2[v]);

        }if(siz+sz[u]<2)return;
        cmax(ans[len[u]],max((ll)mx[u]*mx2[u],(ll)mi[u]*mi2[u]));
        go(u)sum[len[u]]+=(ll)sz[u]*sz[v],sz[u]+=sz[v];
    }
    inline void sol(){
        mx[1]=mx2[1]=-inf,mi[1]=mi2[1]=inf;
        memset(ans,-63,sizeof ans);
        fp(i,2,T)add(fa[i],i);dfs(1);
        fd(i,n-1,0)sum[i]+=sum[i+1],cmax(ans[i],ans[i+1]);
        fp(i,0,n-1)we(sum[i]),we(!sum[i]?0:ans[i]),sr[++C]='\n';
    }
}p;
int main(){
    #ifndef ONLINE_JUDGE
        file("s");
    #endif
    sd(n),gs(s+1);fp(i,1,n)sd(w[i]);
    fd(i,n,1)p.ins(s[i]-'a',w[i]);p.sol();
return Ot(),0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值