时间限制:1s 内存限制 512MB
题目
一年一度的“幻影阁夏日品酒大会”隆重开幕了。大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加。
在大会的晚餐上,调酒师 Rainbow 调制了 n 杯鸡尾酒。这 n 杯鸡尾酒排成一行,其中第 i 杯酒 (1≤i≤n) 被贴上了一个标签 si,每个标签都是 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) 相似”的。特别地,对于任意的 1≤p,q≤n,p≠q,第 p 杯酒和第 q 杯酒都是“0相似”的。
在品尝环节上,品酒师 Freda 轻松地评定了每一杯酒的美味度,凭借其专业的水准和经验成功夺取了“首席品酒家”的称号,其中第 i 杯酒 (1≤i≤n) 的美味度为 ai。现在 Rainbow 公布了挑战环节的问题:本次大会调制的鸡尾酒有一个特点,如果把第 p 杯酒与第 q 杯酒调兑在一起,将得到一杯美味度为 apaq 的酒。现在请各位品酒师分别对于 r=0,1,2,…,n−1,统计出有多少种方法可以选出 2 杯“r相似”的酒,并回答选择 2 杯“r相似”的酒调兑可以得到的美味度的最大值。
数据范围:n<=300000,|ai|<=1000000000
来源
noi2015day2t2
用后缀数组处理出height,然后按照height从大到小排序,每次将i和i-1用并查集合并,并维护每个连通块的最大值,最小值(有负数),和组数即可。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#define N 300010
#define ll long long
using namespace std;
int n,m,val[N],fa[N],size[N],maxn[N],minn[N];
int x[N],y[N],t[N],cnt[N],sa[N],height[N],rank[N];
ll ans[N],sum[N];char s[N];
bool cmp(int *g,int a,int b,int l)
{return g[a]==g[b]&&g[a+l]==g[b+l];}
bool cmp1(const int &x,const int &y)
{return height[x]>height[y];}
void get_sa()
{
for(int i=1;i<=n;i++)cnt[x[i]=s[i]]++;
for(int i=2;i<=m;i++)cnt[i]+=cnt[i-1];
for(int i=n;i;i--)sa[cnt[s[i]]--]=i;
for(int j=1,tot=0;tot<n;j<<=1,m=tot)
{
tot=0;for(int i=n-j+1;i<=n;i++)y[++tot]=i;
for(int i=1;i<=n;i++)if(sa[i]>j)y[++tot]=sa[i]-j;
for(int i=1;i<=n;i++)t[i]=x[y[i]];
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++)cnt[t[i]]++;
for(int i=2;i<=m;i++)cnt[i]+=cnt[i-1];
for(int i=n;i;i--)sa[cnt[t[i]]--]=y[i];
for(int i=1;i<=n;i++)swap(x[i],y[i]);
tot=2;x[sa[1]]=1;
for(int i=2;i<=n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?tot-1:tot++;
}
}
void get_height()
{
for(int i=1;i<=n;i++)rank[sa[i]]=i;
for(int i=1,j,k=0;i<=n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];s[i+k]==s[j+k];k++);
}
int find(int x)
{
if(fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
void solve()
{
for(int i=1;i<=n;i++)
t[i]=i,fa[i]=i,cnt[i]=1,size[i]=1,
maxn[i]=val[sa[i]],minn[i]=val[sa[i]];
sort(t+2,t+n+1,cmp1);
memset(ans,128,sizeof(ans));
for(int i=2;i<=n;i++)
{
int x=t[i],y=x-1,h=height[x];
x=find(x);y=find(y);
sum[h]+=(ll)size[x]*size[y];
ans[h]=max(ans[h],(ll)maxn[x]*maxn[y]);
ans[h]=max(ans[h],(ll)minn[x]*minn[y]);
fa[y]=x;size[x]+=size[y];
maxn[x]=max(maxn[x],maxn[y]);
minn[x]=min(minn[x],minn[y]);
}
for(int i=n-1;i>=0;i--)
sum[i]+=sum[i+1],ans[i]=max(ans[i],ans[i+1]);
}
int main()
{
scanf("%d %s",&n,s+1);m=128;
for(int i=1;i<=n;i++)scanf("%d",&val[i]);
get_sa();get_height();solve();
for(int i=0;i<n;i++)
if(sum[i])printf("%lld %lld\n",sum[i],ans[i]);
else printf("0 0\n");
return 0;
}