• [bzoj 4199][NOI 2015]品酒大会


    传送门

    Description

    一年一度的“幻影阁夏日品酒大会”隆重开幕了。大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品

    酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加。在大会的晚餐上,调酒师Rainbow调制了 n 杯鸡尾酒。

    这 n 杯鸡尾酒排成一行,其中第 i 杯酒 ((1≤i≤n)) 被贴上了一个标签 (s_i),每个标签都是 26 个小写英文字母

    之一。设 Str(l,r) 表示第 l 杯酒到第 r 杯酒的 r-l+1 个标签顺次连接构成的字符串。若 (Str(p,po)=Str(q,qo)) ,其中 (1≤p≤po≤n,1≤q≤qo≤n,p≠q,po-p+1=qo-q+1=r) ,则称第 p 杯酒与第 q 杯酒是“ r 相似”的。当

    然两杯“ r 相似”(r>1)的酒同时也是“ 1 相似”、“ 2 相似”、……、“ (r-1) 相似”的。在品尝环节上,

    品酒师Freda轻松地评定了每一杯酒的美味度,凭借其专业的水准和经验成功夺取了“首席品酒家”的称号,其中

    第 i 杯酒 (1≤i≤n) 的美味度为 (a_i) 。现在Rainbow公布了挑战环节的问题:本次大会调制的鸡尾酒有一个特点

    ,如果把第 p 杯酒与第 q 杯酒调兑在一起,将得到一杯美味度为 (a_p ,a_q) 的酒。现在请各位品酒师分别对于 (r=0,1,2,..,n-1) ,统计出有多少种方法可以选出 2 杯“ r 相似”的酒,并回答选择 2 杯“ r 相似”的酒调兑可以

    得到的美味度的最大值。

    Solution

    构建出(height)数组,然后自上而下合并即可,因为权值有可能是负数,所以对于每个集合,需要维护一下它的最大值和最小值。


    Code 

    #include<bits/stdc++.h>
    #define ll long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    #define MN 300005
    #define M(a) memset(a,0,sizeof a);
    int n,l[MN],r[MN],siz[MN],fa[MN],id[MN];char s[MN];
    ll m[MN],ans[MN];
    int h[MN],p,q,sa[2][MN],rk[2][MN],num[MN];
    inline void build_sa()
    {
    	register int i,j,k,mx;
    	for(i=1;i<=n;++i) num[s[i]-'a'+1]++;
    	for(i=1;i<=26;++i) num[i]+=num[i-1];
    	for(i=1;i<=n;++i) sa[1][num[s[i]-'a'+1]--]=i;
    	for(i=1;i<=n;++i) rk[1][sa[1][i]]=rk[1][sa[1][i-1]]+(s[sa[1][i-1]]!=s[sa[1][i]]);
    	mx=rk[1][sa[1][n]];
    	for(p=1,q=0,k=1;k<=n;k<<=1,p^=1,q^=1)
    	{
    		if(mx==n) break;
    		for(i=1;i<=n;++i) num[rk[p][sa[p][i]]]=i;
    		for(i=n;i;--i) if(sa[p][i]>k) sa[q][num[rk[p][sa[p][i]-k]]--]=sa[p][i]-k;
    		for(i=n-k+1;i<=n;++i) sa[q][num[rk[p][i]]--]=i;
    		for(i=1;i<=n;++i)
    		rk[q][sa[q][i]]=rk[q][sa[q][i-1]]+(rk[p][sa[q][i]]!=rk[p][sa[q][i-1]]||rk[p][sa[q][i]+k]!=rk[p][sa[q][i-1]+k]);
    		mx=rk[q][sa[q][n]];
    	}
    	for(i=k=1;i<=n;++i)
    	{
    		if(rk[p][i]==1) continue;if(k) k--;
         	for(j=sa[p][rk[p][i]-1];j+k<=n&&i+k<=n&&s[i+k]==s[j+k];++k);
            h[i]=k;
    	}
    }
    inline bool cmp(const int&o,const int&oo){return h[o]>h[oo];}
    inline int getf(int x){return fa[x]==x?x:fa[x]=getf(fa[x]);}
    int main()
    {
    	n=read();scanf("%s",s+1);register int i;
    	for(i=1;i<=n;++i) l[i]=r[i]=read();
    	for(i=1;i<=n;++i) id[i]=i,ans[i-1]=-1e18,siz[i]=1,fa[i]=i;
    	build_sa();std::sort(id+1,id+n+1,cmp);
    	for(i=1;i<=n;i++)
        {
            int u=getf(id[i]),v=getf(sa[p][rk[p][id[i]]-1]);
            m[h[id[i]]]+=1ll*siz[u]*siz[v],ans[h[id[i]]]=max(ans[h[id[i]]],max(1ll*l[u]*l[v],1ll*r[u]*r[v]));
            r[u]=max(r[u],r[v]),l[u]=min(l[u],l[v]),siz[u]+=siz[v],fa[v]=u;
        }
        for(i=n-2;i>=0;i--) m[i]+=m[i+1],ans[i]=max(ans[i],ans[i+1]);
        for(i=0;i<n;i++) printf("%lld %lld
    ",m[i],m[i]?ans[i]:0);
        return 0;
    }
    


    Blog来自PaperCloud,未经允许,请勿转载,TKS!

  • 相关阅读:
    动画效果打开层 关闭层
    一个正在加载网页的进度条,加载完后,自动消失?>
    使用ASP.NET AJAX必要的配置
    css静态滤镜 + A:Hover 的效果
    可擦写的涂改文字
    各种遮罩层(lightbox)实现
    oracle 11g 安装
    SMTP协议
    javaoracle驱动包
    批量处理JDBC语句提高处理速度
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/10281044.html
Copyright © 2020-2023  润新知