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

罕见的抄了一发题解……毕竟NOI原题哪有那么容易写出来的道理
并没有什么罕见的算法,不过思路还是很巧妙的
一开始我的想法是用单调栈,而且好像的确有这种算法的std,不过我乱搞了一下午样例都没过于是只好作罢
改为大众并查集做法。
首先很容易发现,对于任意一对r相似,它一定是k(0<k<r)相似的
所以求出height数组后按其中的值排序,然后从大到小做
当前需要处理的串为i和i-1,设前缀长度为k
易知若将两个并查集合并,则当前的前缀在并查集中一定是最小的,所以Ans[k][0]+=两棵树size的乘积(因为任意两两前缀都是k相似的,可以配对)
除了并查集的size,还维护一下并查集的max和min值,
则Ans[k][1]=max(Ans[k][1],Max1*Max2,Min1*Min2)
维护min值是为了防止有很小的复数这种情况(负负得正)
最后因为Ans[i]也是满足Ans[i+1]的,所以做个前缀和合并一下答案就好

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define MAXN (300000+100)
using namespace std;
int wt[MAXN],wa[MAXN],wb[MAXN];
int SA[MAXN],Rank[MAXN],Height[MAXN];
char r[MAXN];
int a[MAXN],cnt;
int ID[MAXN],Father[MAXN];
long long Size[MAXN],Max[MAXN],Min[MAXN],Ans[MAXN][],INF;
int n,m=; bool cmp(int *y,int a,int b,int k)
{
int arank1=y[a];
int brank1=y[b];
int arank2=a+k>=n?-:y[a+k];
int brank2=b+k>=n?-:y[b+k];
return arank1==brank1 && arank2==brank2;
} void Build_SA()
{
int *x=wa,*y=wb;
for (int i=;i<m;++i) wt[i]=;
for (int i=;i<n;++i) wt[x[i]=r[i]]++;
for (int i=;i<m;++i) wt[i]+=wt[i-];
for (int i=n-;i>=;--i) SA[--wt[x[i]]]=i; for (int j=;j<=n;j<<=)
{
int p=;
for (int i=n-j;i<n;++i) y[p++]=i;
for (int i=;i<n;++i) if (SA[i]>=j) y[p++]=SA[i]-j; for (int i=;i<m;++i) wt[i]=;
for (int i=;i<n;++i) wt[x[y[i]]]++;
for (int i=;i<m;++i) wt[i]+=wt[i-];
for (int i=n-;i>=;--i) SA[--wt[x[y[i]]]]=y[i]; m=;swap(x,y);
x[SA[]]=;
for (int i=;i<n;++i)
x[SA[i]]=cmp(y,SA[i],SA[i-],j)?m-:m++;
if (m>=n) break;
}
} void Build_Height()
{
for (int i=;i<n;++i) Rank[SA[i]]=i;
int k=;
Height[]=;
for (int i=;i<n;++i)
{
if (!Rank[i]) continue;
if (k) k--;
int j=SA[Rank[i]-];
while (r[i+k]==r[j+k]) k++;
Height[Rank[i]]=k;
}
} int Find (int x) {return Father[x]==x?x:Father[x]=Find(Father[x]);}
void Merge (int x,int y)
{
int f1=Find(x),f2=Find(y); int k=Height[x];
Ans[k][]+=Size[f2]*Size[f1];
Ans[k][]=max(max(Max[f2]*Max[f1],Min[f2]*Min[f1]),Ans[k][]); Min[f1]=min(Min[f1],Min[f2]);
Max[f1]=max(Max[f1],Max[f2]);
Father[f2]=f1;
Size[f1]+=Size[f2];
} void Solve()
{
for (int i=;i<n;++i)
{
Father[i]=i;
Size[i]=;
Max[i]=Min[i]=a[SA[i]];
}
for (int i=;i<=n-;++i)
if (Find(ID[i])!=Find(ID[i]-))
Merge(ID[i],ID[i]-);
} bool cmp1(int x,int y)
{
return Height[x]>Height[y];
} int main()
{
memset(&INF,0x7f,sizeof(INF));
scanf("%d",&n);
scanf("%s",r);
for (int i=;i<n;++i)
scanf("%d",&a[i]);
Build_SA();
Build_Height();
for (int i=;i<n;++i)
{
ID[i]=i;
Ans[i][]=;
Ans[i][]=-INF;
}
sort(ID,ID+n,cmp1);
Solve();
for (int i=n-;i>=;--i)
{
Ans[i][]+=Ans[i+][];
Ans[i][]=max(Ans[i][],Ans[i+][]);
}
for (int i=;i<n;++i)
printf("%lld %lld\n",Ans[i][],Ans[i][]==?:Ans[i][]);
}

4199. [NOI2015]品酒大会【后缀数组+并查集】的更多相关文章

  1. BZOJ 4199: [Noi2015]品酒大会( 后缀数组 + 并查集 )

    求出后缀数组后, 对height排序, 从大到小来处理(r相似必定是0~r-1相似), 并查集维护. 复杂度O(NlogN + Nalpha(N)) ------------------------- ...

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

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

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

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

  4. [NOI2015] 品酒大会 - 后缀数组,并查集,STL,启发式合并

    [NOI2015] 品酒大会 Description 对于每一个 \(i \in [0,n)\) 求有多少对后缀满足 LCP 长度 \(\le i\) ,并求满足条件的两个后缀权值乘积的最大值. So ...

  5. 【学术篇】NOI2015 品酒大会 后缀数组+并查集

    省选前大致是刷不了几道题了... 所以就找一些裸一点的题目练练板子算了= = 然而这题一点都不裸, 也并不怎么好写... 于是就浪费了将近一下午的时间... 然而还不是因为后缀数组板子不熟= = 首先 ...

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

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

  7. NOI 2015 品酒大会 (后缀数组+并查集)

    题目大意:略 40分暴力还是很好写的,差分再跑个后缀和 和 后缀最大值就行了 一种正解是后缀数组+并查集 但据说还有后缀数组+单调栈的高端操作蒟蒻的我当然不会 后缀数组求出height,然后从大到小排 ...

  8. Uoj #131. 【NOI2015】品酒大会 后缀数组,并查集

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

  9. BZOJ.4199.[NOI2015]品酒大会(后缀数组 单调栈)

    BZOJ 洛谷 后缀自动机做法. 洛谷上SAM比SA慢...BZOJ SAM却能快近一倍... 显然只需要考虑极长的相同子串的贡献,然后求后缀和/后缀\(\max\)就可以了. 对于相同子串,我们能想 ...

  10. 【BZOJ-4199】品酒大会 后缀数组 + 并查集合并集合

    4199: [Noi2015]品酒大会 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 436  Solved: 243[Submit][Status] ...

随机推荐

  1. 如何优雅的爬取 gzip 格式的页面并保存在本地(java实现)

    1. 引言 在爬取汽车销量数据时需要爬取 html 保存在本地后再做分析,由于一些页面的 gzip 编码格式, 获取后要先解压缩,否则看到的是一片乱码.在网络上仔细搜索了下,终于在这里找到了一个优雅的 ...

  2. win Apache服务消失或无法启动

    在bin目录中找到httpd.exe命令,如下图所示.启动cmd,即命令行,使用管理员身份运行,cd至该bin目录下.   使用cmd执行如下命令进行服务的安装:httpd.exe -k instal ...

  3. python Django Ajax基础

    升级版: ajax 创建多对多以及增加示例: views中的接收

  4. mac,macbook 连接蓝牙耳机播放音乐断断续续

    个人的情况是, mac本连的网线,用的无线鼠标, 屋里80多号人都在用笔记本,应该也有好多开着无线的东西 解决方法: mac 或macbook 连接蓝牙耳机播放音乐断断续续的原因, 在网上找了好多方法 ...

  5. time模块,计算时间差

    计算当前时间与所输入的时间的时间差 #1 计算当前时间的时间戳时间 t_now = time.time() # 计算以前的时间的时间戳时间 t_before = input('请输入时间(例如:200 ...

  6. Django基础三之视图函数

    一 Django的视图函数view 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错 ...

  7. js时间与毫秒数互相转换(转)

    [1]js毫秒时间转换成日期时间   var oldTime = (new Date("2017/04/25 19:44:11")).getTime(); //得到毫秒数    / ...

  8. 解决移动端touch事件(touchstart/touchend) 的穿透问题

    情景: 我们在移动端点击事件click对比touchend会有很明显的300ms的延迟,为啥? 浏览器在 click 后会等待约300ms去判断用户是否有双击行为(手机需要知道你是不是想双击放大网页内 ...

  9. Postman Postman接口测试工具使用简介

    Postman接口测试工具使用简介 by:授客 QQ:1033553122 本文主要是对Postman这个接口测试工具的使用做个简单的介绍,仅供参考. 插件安装 1)下载并安装chrome浏览器 2) ...

  10. Flutter 中 ListView 的使用

    这个小例子使用的是豆瓣 API 中 正在上映的电影的开放接口,要实现的主要效果如下: JSON 数据结构 Item 结构 Item 的结构是一个 Card 包含着一个 Row 然后这个 Row 里面左 ...