[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!

原文地址:https://www.cnblogs.com/PaperCloud/p/10281044.html