题目描述

一年一度的“幻影阁夏日品酒大会”隆重开幕了。大会包含品尝和趣味挑战 两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加。

在大会的晚餐上,调酒师 Rainbow 调制了 n 杯鸡尾酒。这 n 杯鸡尾酒排成一行,其中第 n 杯酒 (1 ≤ i ≤ n) 被贴上了一个标签 si​ ,每个标签都是26 个小写 英文字母之一。设 str(l,r) 表示第 l 杯酒到第 r 杯酒的 r - l + 1个标签顺次连接构成的字符串。若 str(p,p0​)=str(q,q0​),其中 1≤p≤p0​≤n, 1≤q≤q0​≤n, p≠q,p0​−p+1=q0​−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 杯酒调兑在一起,将得到一杯美味度为 ap​×aq​ 的 酒。现在请各位品酒师分别对于r=0,1,2,⋯,n−1 ,统计出有多少种方法可以 选出 2杯“ r 相似”的酒,并回答选择2 杯“r 相似”的酒调兑可以得到的美味度的最大值。

输入格式

第 1 行包含 1 个正整数 n ,表示鸡尾酒的杯数。

第 2 行包含一个长度为 n 的字符串 S,其中第 i 个字符表示第 i 杯酒的标签。

第 3 行包含 n 个整数,相邻整数之间用单个空格隔开,其中第i个整数表示第 i 杯酒的美味度ai​ 。

输出格式

包括 n 行。

第 i 行输出 2 个整数,中间用单个空格隔开。第 1 个整 数表示选出两杯“ (i−1) 相似”的酒的方案数,第 2 个整数表示选出两杯 “ (i−1) 相似”的酒调兑可以得到的最大美味度。若不存在两杯“(i−1) 相似” 的酒,这两个数均为 0 。

说明/提示

【样例说明 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 。

【时限1s,内存512M】

跳过其他同专题练习题的原因是,在写完P4248差异以后翻题解区看后缀树的做法,偶然看到有这么一句“品酒大会也可以用这个方法【单调栈】做”

于是我直奔品酒大会,读题五分钟…

恕鄙人才疏学浅,不懂单调栈单调队列,竟然愣是没看出来【事后发现好像真的有这种写法】

手推了一遍样例,感觉就是对于height数组的数值分组进行一堆统计,大数值可以为小数值的分组产生贡献。于是在草稿纸上按着height数组从大到小过了一遍,发现就是这样。但是同数值之间可以产生更复杂的联系,不一定在height定义的排名i和i-1这种范围内。只要前缀相同,排名为i的数组和i-2的数组可能也会产生贡献。

同时height为2的后缀也可能和height为1的后缀对1相似的答案产生贡献…这样又要考虑分组之间的关联。很容易想到倒着先处理height更大的后缀。

但是对于具体怎么处理还是有点头大。看了看刚刚按排名列出来的数组,花了一下产生贡献的分组,发现很显然能产生贡献的一大堆后缀都有相同的起始字母。从这里开始想到倒着处理所有操作,用并查集来维护同一个大组的信息。对于产生贡献的方案数,可以记录一个size数组,按秩合并。而对于最大值贡献,可以记录一下当前集合的最大a值即最大元素,以及当前集合内部元素已经产生的最大贡献。因为先处理的“x相似”的答案对更小的“y相似”的答案都可以产生贡献,所以在合并的时候直接全局变量维护方案数和最大值。

然后死在第二个样例。

仔细一看样例发现只记录集合最大元素显然会死,因为还有负数存在…负负得正,那就再记录一个最小值,一起维护。

然后疯狂通不过样例2,仔细一查居然打错了SA板子…把y[sa[i]]==y[sa[i-1]]写成了y[sa[i]]==y[sa[i]-1]【居然还能过样例1!!】过了样例满心欢喜地提交,被70分砸一脸。然后发现,初始化最小值要到long long的边界…这题数据大到吓死人。

inf设置成1e18,折腾一晚上终于AC。从开始想题到最后写完中间大概经历了三四个小时…期间还因为写炸并查集偷窥题解。怎么说呢,NOI的题果然不好做_(:з」∠)_

偷偷感谢题解区大佬。

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const long long maxn=;
const long long inf=1e18;
long long n,m,a[maxn];
long long ans[maxn],max1[maxn],ans1,ans2=-inf,number[maxn];
char s[maxn];
long long c[maxn],x[maxn],y[maxn],sa[maxn],fa[maxn],height[maxn],siz[maxn],maxx[maxn],minn[maxn];
vector<long long>h[maxn];
long long get(long long x){
if(fa[x]==x)return x;
else return fa[x]=get(fa[x]);
}
void getHEIGHT(){
long long k=;
for(long long i=;i<=n;i++){
if(x[i]==){
k=;
height[]=;
continue;
}
if(k)k--;
long long j=sa[x[i]-];
while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
height[x[i]]=k;
}
}
void getSA(){
for(long long i=;i<=n;i++)c[s[i]]++,x[i]=s[i];
for(long long i=;i<=m;i++)c[i]+=c[i-];
for(long long i=n;i>=;i--)sa[c[x[i]]--]=i;
for(long long k=;k<=n;k<<=){
long long num=;
for(long long i=n-k+;i<=n;i++)y[++num]=i;
for(long long i=;i<=n;i++)if(sa[i]>k)y[++num]=sa[i]-k;
for(long long i=;i<=m;i++)c[i]=;
for(long long i=;i<=n;i++)c[x[i]]++;
for(long long i=;i<=m;i++)c[i]+=c[i-];
for(long long i=n;i>=;i--)sa[c[x[y[i]]]--]=y[i],y[i]=;
swap(x,y);
x[sa[]]=;
num=;
for(long long i=;i<=n;i++){
x[sa[i]]=(y[sa[i]]==y[sa[i-]]&&y[sa[i]+k]==y[sa[i-]+k])?num:++num;
}
if(num==n)break;
m=num;
}
getHEIGHT();
}
void work(long long x,long long y){
if(siz[x]<siz[y])swap(x,y);
fa[y]=x;
ans1+=siz[x]*siz[y];
siz[x]+=siz[y];
number[x]=max(max(number[x],number[y]),max(maxx[x]*maxx[y],minn[x]*minn[y]));
maxx[x]=max(maxx[x],maxx[y]);
minn[x]=min(minn[x],minn[y]);
ans2=max(ans2,number[x]);
}
int main()
{
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
scanf("%lld",&n);
scanf("%s",s+);
for(int i=;i<=n;i++)scanf("%lld",&a[i]);
m=;
getSA();
for(int i=;i<=n;i++)h[height[i]].push_back(i);
for(long long i=;i<=n;i++){
fa[i]=i;
siz[i]=;
maxx[i]=minn[i]=a[sa[i]];
number[i]=-inf;
}
for(long long i=n-;i>=;i--){
for(long long j=;j<h[i].size();j++){
long long x=h[i][j];
work(get(x-),get(x));
}
if(ans1){
ans[i]=ans1;
max1[i]=ans2;
}
}
for(long long i=;i<n;i++){
printf("%lld %lld\n",ans[i],max1[i]);
}
return ;
}

洛谷P2178 [NOI2015]品酒大会的更多相关文章

  1. 洛谷 P2178 [NOI2015]品酒大会 解题报告

    P2178 [NOI2015]品酒大会 题目描述 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战 两个环节,分别向优胜者颁发"首席品酒家"和 ...

  2. 洛谷P2178 [NOI2015]品酒大会 后缀数组+单调栈

    P2178 [NOI2015]品酒大会 题目链接 https://www.luogu.org/problemnew/show/P2178 题目描述 一年一度的"幻影阁夏日品酒大会" ...

  3. 洛谷P2178 [NOI2015]品酒大会(后缀自动机 线段树)

    题意 题目链接 Sol 说一个后缀自动机+线段树的无脑做法 首先建出SAM,然后对parent树进行dp,维护最大次大值,最小次小值 显然一个串能更新答案的区间是\([len_{fa_{x}} + 1 ...

  4. P2178 [NOI2015]品酒大会

    思路 在后缀树上进行一些操作就好了 后缀树上LCA的maxlen就是两个后缀的LCP的长度了 然后统计每个点作为LCA的次数和最大值.次大值.最小值.次小值 然后就做完了 代码 #include &l ...

  5. BZOJ 4199: [Noi2015]品酒大会 [后缀数组 带权并查集]

    4199: [Noi2015]品酒大会 UOJ:http://uoj.ac/problem/131 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 ...

  6. [UOJ#131][BZOJ4199][NOI2015]品酒大会 后缀数组 + 并查集

    [UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...

  7. 【BZOJ4199】[Noi2015]品酒大会 后缀数组+并查集

    [BZOJ4199][Noi2015]品酒大会 题面:http://www.lydsy.com/JudgeOnline/wttl/thread.php?tid=2144 题解:听说能用SAM?SA默默 ...

  8. [UOJ#131][BZOJ4199][NOI2015]品酒大会

    [UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...

  9. BZOJ_4199_[Noi2015]品酒大会_后缀自动机

    BZOJ_4199_[Noi2015]品酒大会_后缀自动机 Description 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 酒家”和“首席 ...

随机推荐

  1. Python-面向对象之封装与多态

    目录 组合 什么是组合 使用组合的目的 如何使用组合 封装 什么是封装 为什么要封装 如何封装 访问限制机制 什么是访问限制机制 访问限制机制的目的 如何使用访问限制 property 什么是prop ...

  2. Django 操作Cookie与Session

    目录 Cookie Session Django中操作Cookie 基本操作 基于cookie的登录装饰器 Django中操作Session 基本操作 Session流程解析 基于session的登录 ...

  3. Jtopo使用中link中文字与link平行

    修改源代码如下 //新增 a.translate(e ,f ); a.rotate(Math.atan((d.y-c.y)/(d.x-c.x))); //修改 a.fillText(this.text ...

  4. iPhoneX适配随笔

    1.安全区域 2.NavigationBar 和 TabBar的xib示意图 两个View要相同的效果,坐标不同 UIButton *btn = [UIButton buttonWithType:UI ...

  5. Python基础---序列对象

    一.序列简介 数据结构是通过某种方式组织在一起的元素的集合. 容器(Container)是一种Python的数据结构,基本上是包含其他对象的任意对象.序列和映射(如字典)是两类主要的容器.集合(Set ...

  6. jdk11下载安装及环境变量配置

    jdk11下载安装及环境变量配置 官网地址:https://www.oracle.com/technetwork/java/javase/downloads/jdk11-downloads-50666 ...

  7. windows API 第 11 篇 GetCurrentDirectory SetCurrentDirectory

    GetCurrentDirectory函数获得当前文件所在的目录,并不是进程的目录(debug 和 release),它和GetCommandLine不同这里只讲 GetCurrentDirector ...

  8. [转]【全面解禁!真正的Expression Blend实战开发技巧】第八章 FluidMoveBehavior完全解析之一漂浮移动

    好久没更新博客了,今天如果没急事,准备连发三篇,完全讲解Blend最牛的元素-“FluidMoveBehavior”.我向大家保证这三章一定非常精彩,不看你肯定后悔.我相信这三篇文章发表后,国内很多s ...

  9. __name__ = '__main__'

    有句话经典的概括了这段代码的意义: “Make a script both importable and executable” 意思就是说让你写的脚本模块既可以导入到别的模块中用,另外该模块自己也可 ...

  10. csp-s模拟测试b组加餐antipalindome,randomwalking,string题解

    题面:https://www.cnblogs.com/Juve/articles/11599318.html antipalindome: 打表找规律? 对于一个回文串,我们只要保证3位以内不回文即可 ...