洛谷P2178 [NOI2015]品酒大会
题目描述
一年一度的“幻影阁夏日品酒大会”隆重开幕了。大会包含品尝和趣味挑战 两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加。
在大会的晚餐上,调酒师 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]品酒大会的更多相关文章
- 洛谷 P2178 [NOI2015]品酒大会 解题报告
P2178 [NOI2015]品酒大会 题目描述 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战 两个环节,分别向优胜者颁发"首席品酒家"和 ...
- 洛谷P2178 [NOI2015]品酒大会 后缀数组+单调栈
P2178 [NOI2015]品酒大会 题目链接 https://www.luogu.org/problemnew/show/P2178 题目描述 一年一度的"幻影阁夏日品酒大会" ...
- 洛谷P2178 [NOI2015]品酒大会(后缀自动机 线段树)
题意 题目链接 Sol 说一个后缀自动机+线段树的无脑做法 首先建出SAM,然后对parent树进行dp,维护最大次大值,最小次小值 显然一个串能更新答案的区间是\([len_{fa_{x}} + 1 ...
- P2178 [NOI2015]品酒大会
思路 在后缀树上进行一些操作就好了 后缀树上LCA的maxlen就是两个后缀的LCP的长度了 然后统计每个点作为LCA的次数和最大值.次大值.最小值.次小值 然后就做完了 代码 #include &l ...
- BZOJ 4199: [Noi2015]品酒大会 [后缀数组 带权并查集]
4199: [Noi2015]品酒大会 UOJ:http://uoj.ac/problem/131 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 ...
- [UOJ#131][BZOJ4199][NOI2015]品酒大会 后缀数组 + 并查集
[UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...
- 【BZOJ4199】[Noi2015]品酒大会 后缀数组+并查集
[BZOJ4199][Noi2015]品酒大会 题面:http://www.lydsy.com/JudgeOnline/wttl/thread.php?tid=2144 题解:听说能用SAM?SA默默 ...
- [UOJ#131][BZOJ4199][NOI2015]品酒大会
[UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...
- BZOJ_4199_[Noi2015]品酒大会_后缀自动机
BZOJ_4199_[Noi2015]品酒大会_后缀自动机 Description 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 酒家”和“首席 ...
随机推荐
- Django之ORM查询优化
目录 only 和 defer select_related 和 prefetch_related ORM字段参数 choices res = models.Book.objects.all() # ...
- BZOJ2741:[FOTILE模拟赛]L
Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 .. ...
- Python面向对象学习
以下面例子作为面向对象基础介绍,类比java里的面向对象既可以,大同小异 class Employee(): raiseAmount=1.04 employeeNum= def __init__(se ...
- com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no queue 'springCloudBus.anonymous.6Xa99MDZTJyHKdPqMyoVEA' in
项目启动报此异常,解决方式:用root权限登陆rabbitmq,admin处添加vhost
- JS里面function和Function的区别
js里Function 与 function的不一样的,不仅仅是大小写的问题. 简单点说:大写的Function是一个类 ,而小写的function是一个对象. Function是一个构造器,func ...
- JEECG-Boot 项目介绍——基于代码生成器的快速开发平台(Springboot前后端分离)
Jeecg-Boot 是一款基于代码生成器的智能开发平台!采用前后端分离架构:SpringBoot,Mybatis,Shiro,JWT,Vue&Ant Design.强大的代码生成器让前端和后 ...
- shell脚本实现读取一个文件中的某一列,并进行循环处理
shell脚本实现读取一个文件中的某一列,并进行循环处理 1) for循环 #!bin/bash if [ ! -f "userlist.txt" ]; then echo &qu ...
- HTML给div设置百分比高度无效的解决方式 - 库塔姆斯 - CSDN博客
原文:HTML给div设置百分比高度无效的解决方式 - 库塔姆斯 - CSDN博客 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/HobHunter ...
- 很好用的API管理--Swagger
1.打开NuGet程序包 2.安装下面两个程序包 3.安装完后会出现SwaggerConfig.cs类,并修改里面的内容 代码: [assembly: PreApplicationStartMetho ...
- kuangbin带我飞QAQ 并查集
1. POJ 2236 给出N个点,一开始图是空白的,两个操作,一个是增加一个点(给出坐标),一个是查询两个点间是否相通,当两点间的距离小于D或者两点通过其他点间接相连时说这两个点相通.并查集维护,每 ...