zoukankan      html  css  js  c++  java
  • 【洛谷P2178】品酒大会

    题目

    题目链接:https://www.luogu.com.cn/problem/P2178
    一年一度的“幻影阁夏日品酒大会”隆重开幕了。大会包含品尝和趣味挑战 两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加。
    在大会的晚餐上,调酒师 Rainbow 调制了 (n) 杯鸡尾酒。这 (n) 杯鸡尾酒排成一行,其中第 (n) 杯酒 ((1 ≤ i ≤ n)) 被贴上了一个标签 (s_i) ,每个标签都是 (26) 个小写 英文字母之一。设 (str(l, r)) 表示第 (l) 杯酒到第 (r) 杯酒的 (r - l + 1) 个标签顺次连接构成的字符串。若 (str(p, p_0) = str(q, q_0)),其中 (1 ≤ p ≤ p_0 ≤ n), (1 ≤ q ≤ q_0 ≤ n), (p ≠ q)(p_0-p+1 = q_0 - 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)) 的 美味度为 (a_i) 。现在 Rainbow 公布了挑战环节的问题:本次大会调制的鸡尾酒有一个特点,如果把第 (p) 杯酒与第 (q) 杯酒调兑在一起,将得到一杯美味度为 (a_p imes a_q) 的 酒。现在请各位品酒师分别对于 (r = 0,1,2,⋯,n-1) ,统计出有多少种方法可以 选出 (2) 杯“ (r) 相似”的酒,并回答选择 (2) 杯“(r) 相似”的酒调兑可以得到的美味度的最大值。

    思路

    直接上后缀数组求出 height,然后按照 height 从大到小枚举,并查集合并两个块,同时维护好每个块中的最大值,最小值和大小即可。
    时间复杂度 (O(nlog n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=300010;
    int n,m,a[N],sa[N],rk[N],x[N],y[N],c[N],height[N],father[N],siz[N],maxa[N],mina[N];
    ll ans[N][2];
    char s[N];
    vector<int> pos[N];
    
    void SA()
    {
    	for (int i=1;i<=n;i++) x[i]=s[i],c[x[i]]++;
    	for (int i=2;i<=m;i++) c[i]+=c[i-1];
    	for (int i=n;i>=1;i--) sa[c[x[i]]--]=i;
    	for (int k=1;k<=n;k<<=1)
    	{
    		int num=0;
    		for (int i=n-k+1;i<=n;i++) y[++num]=i;
    		for (int i=1;i<=n;i++) if (sa[i]>k) y[++num]=sa[i]-k;
    		for (int i=1;i<=m;i++) c[i]=0;
    		for (int i=1;i<=n;i++) c[x[i]]++;
    		for (int i=2;i<=m;i++) c[i]+=c[i-1];
    		for (int i=n;i>=1;i--) sa[c[x[y[i]]]--]=y[i],y[i]=0;
    		swap(x,y);
    		x[sa[1]]=num=1;
    		for (int i=2;i<=n;i++)
    			x[sa[i]]=(y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
    		m=num;
    		if (n==m) break;
    	}
    }
    
    void geth()
    {
    	for (int i=1;i<=n;i++) rk[sa[i]]=i;
    	for (int i=1,k=0;i<=n;i++)
    	{
    		if (k) k--;
    		int j=sa[rk[i]-1];
    		while (s[i+k]==s[j+k]) k++;
    		height[rk[i]]=k;
    	}
    }
    
    int find(int x)
    {
    	return x==father[x]?x:father[x]=find(father[x]);
    }
    
    int main()
    {
    	scanf("%d%s",&n,s+1);
    	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    	m='z'+1;
    	SA(); geth();
    	for (int i=1;i<=n;i++)
    	{
    		pos[height[i]].push_back(i);
    		father[i]=i; siz[i]=1; maxa[i]=mina[i]=a[sa[i]];
    	}
    	ans[n][1]=-5e18;
    	for (int i=n-1;i>=0;i--)
    	{
    		ans[i][0]=ans[i+1][0]; ans[i][1]=ans[i+1][1];
    		for (int j=0;j<pos[i].size();j++)
    		{
    			int x=find(pos[i][j]),y=find(pos[i][j]-1);
    			if (x!=y)
    			{
    				ans[i][0]+=1LL*siz[x]*siz[y];
    				ans[i][1]=max(ans[i][1],max(1LL*maxa[x]*maxa[y],1LL*mina[x]*mina[y]));
    				ans[i][1]=max(ans[i][1],max(1LL*mina[x]*maxa[y],1LL*maxa[x]*mina[y]));
    				if (siz[x]<siz[y])
    				{
    					siz[y]+=siz[x]; father[x]=y;
    					maxa[y]=max(maxa[y],maxa[x]);
    					mina[y]=min(mina[y],mina[x]);
    				}
    				else
    				{
    					siz[x]+=siz[y]; father[y]=x;
    					maxa[x]=max(maxa[x],maxa[y]);
    					mina[x]=min(mina[x],mina[y]);
    				}
    			}
    		}
    	}
    	for (int i=0;i<n;i++)
    	{
    		if (ans[i][1]==-5e18) ans[i][1]=0;
    		printf("%lld %lld
    ",ans[i][0],ans[i][1]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    在spring官网上下载历史版本的spring插件,springsource-tool-suite
    转载---VB DorpDownList控件 添加选项
    VB,将"秒"转成"时分秒"格式
    VB.NET 改变datatable数据类型
    转载--- C# 图片与base64编码 互相转换
    转载--- php5.6:Call to undefined function curl_init()的解决办法
    转载--- navicat12破解版(英文、中文)
    转载---mysql导出事件、存储过程、函数、库表
    C# 读取mysql blob字段(两种方式)
    转载---安装mysql5.7,遇到的问题
  • 原文地址:https://www.cnblogs.com/stoorz/p/14235587.html
Copyright © 2011-2022 走看看