品酒大会

来源:互联网 发布:易语言捕鱼游戏源码 编辑:程序博客网 时间:2024/04/29 18:38

品酒大会

时间限制: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 longusing 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;}
0 0
原创粉丝点击