当前位置: 代码迷 >> 综合 >> [bzoj4199][后缀数组][并查集]品酒大会
  详细解决方案

[bzoj4199][后缀数组][并查集]品酒大会

热度:38   发布时间:2023-12-19 05:13:15.0

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 相似”的酒调兑可以 得到的美味度的最大值。

Input

输入文件的第1行包含1个正整数 n ,表示鸡尾酒的杯数。 第 2 行包含一个长度为 n 的字符串 S ,其中第 i 个字符表示第 i
杯酒的标签。 第 3 行包含 n 个整数,相邻整数之间用单个空格隔开,其中第 i 个整数表示第 i 杯酒的美味度 a_i 。
n=300,000 |a_i |≤1,000,000,000

Output

输出文件包括 n 行。第 i 行输出 2 个整数,中间用单个空格隔开。

第 1 个整数表示选出两杯“ (i-1)” ” 相似”的酒的方案数, 第 2 个整数表示选出两杯“ (i-1)
相似”的酒调兑可以得到的最大美味度。 若不存在两杯“ (i-1) 相似”的酒,这两个数均为 0 。

Sample Input

10

ponoiiipoi

2 1 4 7 4 8 3 6 4 7

Sample Output

45 56

10 56

3 32

0 0

0 0

0 0

0 0

0 0

0 0

0 0

HINT

【样例说明1】

用二元组 (p,q) 表示第 p 杯酒与第 q 杯酒。

0 相似:所有 45 对二元组都是 0 相似的,美味度最大的是 8×7=56 。

1 相似: (1,8) (2,4) (2,9) (4,9) (5,6) (5,7) (5,10) (6,7) (6,10) (7,10)
,最大的 8×7=56 。

2 相似: (1,8) (4,9) (5,6) ,最大的 4×8=32 。

没有 3,4,5,?,9 相似的两杯酒,故均输出 0 。

题解

不让 log2 l o g 2 的SA过的题都不是好题哼
很显然是求任意两个后缀的最长公共前缀
先把SA和height跑出来
倒着离线
任意两个后缀的最长公共前缀就是他们连续一段的height的最小值
枚举答案,每次把height>=枚举的数的位置标为true,如果连成一段了就可以更新答案呀。
维护一个最大次大和最小次小。因为数可能是负数
并查集优化就过了…
哼不让 log2 l o g 2 过的人就是坏淫

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#define inf (1<<30)
#define LL long long
#define ULL unsigned long long
#define HA 569
using namespace std;
inline int read()
{int f=1,x=0;char ch=getchar();while(ch<'0' || ch>'9'){
   if(ch=='-')f=-1;ch=getchar();}while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;
}
inline void write(LL x)
{if(x<0)putchar('-'),x=-x;if(x>9)write(x/10);putchar(x%10+'0');
}
inline void print(LL x){write(x);putchar(' ');}
struct node
{LL g1,g2;node(){}node(LL _g1,LL _g2){g1=_g1;g2=_g2;}friend bool operator <(node n1,node n2){
   return n1.g1*n1.g2<n2.g1*n2.g2;}
};
struct gggg
{LL g1,g2;gggg(){}gggg(LL _g1,LL _g2){g1=_g1;g2=_g2;}friend bool operator <(gggg n1,gggg n2){
   return n1.g1*n1.g2<n2.g1*n2.g2;}
};
priority_queue<node> heap;
priority_queue<gggg> pppp;
vector<int> li[300005];
LL a1[300005],a2[300005];
char ch[300005];
ULL hash[300005],pre[300005];
int p[300005],height[300005],a[300005],tmp[300005],n;
int Rsort[300005],Rank[300005],sa1[300005],sa2[300005];
int tt[300005];
void get_sa(int len,int m)
{memcpy(Rank,tmp,sizeof(Rank));memset(Rsort,0,sizeof(Rsort));for(int i=1;i<=len;i++)Rsort[Rank[i]]++;for(int i=1;i<=m;i++)Rsort[i]+=Rsort[i-1];for(int i=len;i>=1;i--)sa1[Rsort[Rank[i]]--]=i;int ln=1,p=0;while(p<len){int k=0;for(int i=len-ln+1;i<=len;i++)sa2[++k]=i;for(int i=1;i<=len;i++)if(sa1[i]-ln>0)sa2[++k]=sa1[i]-ln;memset(Rsort,0,sizeof(Rsort));for(int i=1;i<=len;i++)Rsort[Rank[i]]++;for(int i=1;i<=m;i++)Rsort[i]+=Rsort[i-1];for(int i=len;i>=1;i--)sa1[Rsort[Rank[sa2[i]]]--]=sa2[i];memcpy(tt,Rank,sizeof(tt));Rank[sa1[1]]=1;p=1;for(int i=2;i<=len;i++){if(tt[sa1[i]]!=tt[sa1[i-1]] || tt[sa1[i]+ln]!=tt[sa1[i-1]+ln])p++;Rank[sa1[i]]=p;}ln*=2;m=p;}
}
/*inline bool check(int u,int v,int ln) {ULL gg=pre[ln];return hash[u+ln-1]-hash[u-1]*gg==hash[v+ln-1]-hash[v-1]*gg; } inline bool cmp(int n1,int n2) {int l=1,r=n,ret=0;//二分长度 while(l<=r){int mid=(l+r)/2;if(mid>min(n-n1+1,n-n2+1))r=mid-1;if(!check(n1,n2,mid))r=mid-1;else ret=mid,l=mid+1;}return ch[n1+ret]-'a'<ch[n2+ret]-'a'; }*/
inline void gethe()
{int j,k=0;for(int i=1;i<=n;i++){j=p[Rank[i]-1];if(k)k--;while(ch[i+k]==ch[j+k])k++;height[Rank[i]]=k;}
}
bool v[300005];
int fa[300005],tot[300005],mx[300005][2],mn[300005][2],gg[5];
int findfa(int x){
   return fa[x]==x?fa[x]:fa[x]=findfa(fa[x]);}
inline void meg(int u,int v)
{fa[u]=v;tot[v]+=tot[u];gg[1]=mx[u][0],gg[2]=mx[u][1],gg[3]=mx[v][0],gg[4]=mx[v][1];sort(gg+1,gg+1+4);mx[v][0]=gg[4];mx[v][1]=gg[3];gg[1]=mn[u][0],gg[2]=mn[u][1],gg[3]=mn[v][0],gg[4]=mn[v][1];sort(gg+1,gg+1+4);mn[v][0]=gg[1];mn[v][1]=gg[2];
}
LL aaa;
int main()
{//freopen("a.in","r",stdin);//freopen("a.out","w",stdout);n=read();scanf("%s",ch+1);
/* pre[0]=1;for(int i=1;i<=n;i++){hash[i]=hash[i-1]*HA+ch[i]-'a';pre[i]=pre[i-1]*HA;p[i]=i;}sort(p+1,p+1+n,cmp);*/for(int i=1;i<=n;i++)tmp[i]=ch[i]-'a'+1;get_sa(n,30);for(int i=1;i<=n;i++)p[i]=sa1[i],Rank[p[i]]=i;for(int i=1;i<=n;i++)a[i]=read();gethe();memset(v,false,sizeof(v));
/* for(int i=1;i<=n;i++){for(int j=p[i];j<=n;j++)printf("%c",ch[j]);puts("");printf(" HEIGHT : %d\n",height[i]);}*/for(int i=1;i<=n;i++)li[height[i]].push_back(i),fa[i]=i,tot[i]=1,mx[i][0]=mn[i][0]=a[p[i]],mx[i][1]=-inf,mn[i][1]=inf;LL sum=0;aaa=-(1LL<<63-1);for(int i=n-1;i>=0;i--){for(int j=0;j<li[i].size();j++){int po=li[i][j];v[po]=true;sum++;if(po==1)sum--;if(v[po-1]){int pp=findfa(po),q=findfa(po-1);if(tot[q]!=po-1)sum+=((LL)tot[pp]*(tot[q]+1)-tot[pp]);else sum+=((LL)tot[pp]*tot[q]-tot[pp]);int la=tot[q];meg(pp,q);/* heap.push(node(mx[q][0],max(mx[q][1],a[p[po-1-la]])));pppp.push(gggg(mn[q][0],min(mn[q][1],a[p[po-1-la]])));*/aaa=max(aaa,max((LL)mx[q][0]*max(mx[q][1],a[p[po-1-la]]),(LL)mn[q][0]*min(mn[q][1],a[p[po-1-la]])));}if(v[po+1]){int pp=findfa(po),q=findfa(po+1);if(tot[pp]!=po)sum+=((LL)(tot[pp]+1)*tot[q]-tot[q]);else sum+=((LL)tot[pp]*tot[q]-tot[q]);int la=tot[pp];meg(pp,q);/*heap.push(node(mx[q][0],max(mx[q][1],a[p[po-la]])));pppp.push(gggg(mn[q][0],min(mn[q][1],a[p[po-la]])));*/aaa=max(aaa,max((LL)mx[q][0]*max(mx[q][1],a[p[po-la]]),(LL)mn[q][0]*min(mn[q][1],a[p[po-la]])));}if(!v[po-1]&&!v[po+1]){/*heap.push(node(mx[po][0],max(a[p[po-1]],mx[po][1])));pppp.push(gggg(mn[po][0],min(mn[po][1],a[p[po-1]])));*/aaa=max(aaa,max((LL)mx[po][0]*max(mx[po][1],a[p[po-1]]),(LL)mn[po][0]*min(mn[po][1],a[p[po-1]])));}}a1[i]=sum;if(aaa!=-(1LL<<63-1))a2[i]=aaa;}for(int i=0;i<n;i++){print(a1[i]);print(a2[i]);puts("");//printf("%lld %lld\n",a1[i],a2[i]);}return 0;
}