【BZOJ-4199】品酒大会 后缀数组 + 并查集合并集合
4199: [Noi2015]品酒大会
Time Limit: 10 Sec Memory Limit: 512 MB
Submit: 436 Solved: 243
[Submit][Status][Discuss]
Description
一年一度的“幻影阁夏日品酒大会”隆重开幕了。大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加。
在大会的晚餐上,调酒师 Rainbow 调制了 nn 杯鸡尾酒。这 nn 杯鸡尾酒排成一行,其中第 ii 杯酒 (1≤i≤n1≤i≤n) 被贴上了一个标签 sisi,每个标签都是 2626 个小写英文字母之一。设 Str(l,r)Str(l,r) 表示第 ll 杯酒到第 rr 杯酒的 r−l+1r−l+1 个标签顺次连接构成的字符串。 若 Str(p,po)=Str(q,qo)Str(p,po)=Str(q,qo),其中 1≤p≤po≤n1≤p≤po≤n,1≤q≤qo≤n1≤q≤qo≤n,p≠qp≠q,po−p+1=qo−q+1=rpo−p+1=qo−q+1=r,则称第 pp 杯酒与第 qq 杯酒是“rr相似” 的。当然两杯“rr相似” (r>1r>1)的酒同时也是“11 相似”、“22 相似”、……、“(r−1)(r−1) 相似”的。特别地,对于任意的 1≤p,q≤n1≤p,q≤n,p≠qp≠q,第 pp 杯酒和第 qq 杯酒都是“00相似”的。
在品尝环节上,品酒师 Freda 轻松地评定了每一杯酒的美味度,凭借其专业的水准和经验成功夺取了“首席品酒家”的称号,其中第 ii 杯酒 (1≤i≤n1≤i≤n) 的美味度为 aiai。现在 Rainbow 公布了挑战环节的问题:本次大会调制的鸡尾酒有一个特点,如果把第 pp 杯酒与第 qq 杯酒调兑在一起,将得到一杯美味度为 apaqapaq 的酒。现在请各位品酒师分别对于 r=0,1,2,…,n−1r=0,1,2,…,n−1,统计出有多少种方法可以选出 22 杯“rr相似”的酒,并回答选择 22 杯“rr相似”的酒调兑可以得到的美味度的最大值。
Input
输入文件的第 11 行包含 11 个正整数 nn,表示鸡尾酒的杯数。
第 22 行包含一个长度为 nn 的字符串 SS,其中第 ii 个字符表示第 ii 杯酒的标签。
第 33 行包含 nn 个整数,相邻整数之间用单个空格隔开,其中第 ii 个整数表示第 ii 杯酒的美味度 aiai。
Output
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
用二元组 (p,q)(p,q) 表示第 pp 杯酒与第 qq 杯酒。
0 相似:所有 4545 对二元组都是 00 相似的,美味度最大的是 8×7=568×7=56。
1 相似:(1,8)(1,8) (2,4)(2,4) (2,9)(2,9) (4,9)(4,9) (5,6)(5,6) (5,7)(5,7) (5,10)(5,10) (6,7)(6,7) (6,10)(6,10) (7,10)(7,10),最大的 8×7=568×7=56。
2 相似:(1,8)(1,8) (4,9)(4,9) (5,6)(5,6),最大的 4×8=324×8=32。
没有 3,4,5,…,93,4,5,…,9 相似的两杯酒,故均输出 00。
Source
Solution
BZOJ题面崩了,转自UOJ
后缀数组+并查集合并集合
题目大意:给出一个n,和一个长度为n的字符串,每一个字符有一个价值Val[i],定义一个相似r相似,即满足位置p,q开始r个字符,完全匹配,则称是r相似;每对r相似有一个权值为Val[p]*Val[q],题目求对于r=0~n-1,输出满足r相似的对数,和最大的价值
有种LCP的样子,所以考虑后缀数组,第一问,肯定是对Height做文章
发现,对于任何一对,如果满足r相似,则必然满足r-1相似,那么r-1相似的答案可以通过r相似的答案得到..所以可以对Height从大到小排序,然后搞第一问..
至于第二问,想的是在做第一问的基础上顺便更新第二问,这样问题就变成了定长的公共子串..好像没有搞过的样子
自己的愚见:对于Height分组,限制定长二分一下,似乎可以得到第一问..但效率不高啊>..
正解:对height排序.合并当前的两个字符串,并维护他们的答案,这里可以应用并查集
那么打他们两个对方案数的贡献就是所在集合的个数的乘积,这样从大到小枚举每个后缀,将rank[i]和rank[i-1]的两个后缀合并,更新答案即可
值得注意:
在动态维护集合的合并 的适合,需要统计4个量:最大maxx[],最小minn[],容量size[],代表元素fa[],最大最小是用来统计第二问的答案,容量则计算第一问..
一开始自己忘记了统计最小,因为如果最小值都小于零且绝对值很大,他们的价值的乘积是大于最大值的乘积的..(一开始就忘记了QAQ)
Code
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<cmath>
- using namespace std;
- int read()
- {
- int x=,f=; char ch=getchar();
- while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
- while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
- return x*f;
- }
- #define maxn 300010
- int len,val[maxn];
- int S[maxn]; int SA[maxn];
- int ws[maxn],wa[maxn],wv[maxn],wb[maxn];
- int cmp(int *r,int a,int b,int l)
- {
- return r[a]==r[b]&&r[a+l]==r[b+l];
- }
- void DA(int *r,int *sa,int n,int m)
- {
- int p,*x=wa,*y=wb,*t;
- for (int i=; i<m; i++) ws[i]=;
- for (int i=; i<n; i++) ws[x[i]=r[i]]++;
- for (int i=; i<m; i++) ws[i]+=ws[i-];
- for (int i=n-; i>=; i--) sa[--ws[x[i]]]=i;
- p=; for (int j=; p<n; j*=,m=p)
- {
- 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<n; i++) wv[i]=x[y[i]];
- for (int i=; i<m; i++) ws[i]=;
- for (int i=; i<n; i++) ws[wv[i]]++;
- for (int i=; i<m; i++) ws[i]+=ws[i-];
- for (int i=n-; i>=; i--) sa[--ws[wv[i]]]=y[i];
- t=x; x=y; y=t; p=; x[sa[]]=;
- for (int i=; i<n; i++)
- x[sa[i]]=cmp(y,sa[i-],sa[i],j)?p-:p++;
- }
- }
- int rank[maxn],height[maxn];
- void calheight(int *r,int *sa,int n)
- {
- int k=;
- for (int i=; i<=n; i++) rank[sa[i]]=i;
- for (int i=; i<n; height[rank[i++]]=k)
- {k?k--:;for (int j=sa[rank[i]-]; r[i+k]==r[j+k]; k++);}
- }
- int fa[maxn],maxx[maxn],minn[maxn],size[maxn];
- void init()
- {for(int i=; i<=len; i++) fa[i]=i,size[i]=,maxx[rank[i-]]=minn[rank[i-]]=val[i];}
- int find(int x)
- {if (fa[x]==x) return x; return fa[x]=find(fa[x]);}
- void merge(int x,int y)
- {
- int fx=find(x),fy=find(y);
- if (fx!=fy)
- {
- fa[fy]=fx;
- maxx[fx]=max(maxx[fx],maxx[fy]);
- size[fx]=size[fx]+size[fy];
- minn[fx]=min(minn[fx],minn[fy]);
- }
- }
- struct Node
- {
- int height,a,b;
- bool operator < (const Node & A) const
- {return height>A.height;}
- }g[maxn];
- long long ans1[maxn],ans2[maxn];
- void work()
- {
- //len--;
- for (int i=; i<=len; i++) g[i-].height=height[i],g[i-].a=i,g[i-].b=i-;
- sort(g+,g+len);
- memset(ans2,,sizeof(ans2));
- for (int i=g[].height,j=; i>=; i--)
- {
- ans1[i]=ans1[i+],ans2[i]=ans2[i+];
- for ( ;j<len && g[j].height==i; j++)
- {
- int x=find(g[j].a),y=find(g[j].b);
- ans2[i]=max(ans2[i],(long long)maxx[x]*maxx[y]);
- ans2[i]=max(ans2[i],(long long)minn[x]*minn[y]);
- ans1[i]+=(long long)size[x]*size[y];
- merge(g[j].a,g[j].b);
- }
- }
- for (int i=; i<len; i++) if (!ans1[i]) ans2[i]=;
- }
- int main()
- {
- // freopen("savour.in","r",stdin);
- // freopen("savour.out","w",stdout);
- len=read();
- char St[maxn]; scanf("%s",St);
- for (int i=; i<len; i++) S[i]=St[i]-'a'+; S[len]=;
- for (int i=; i<=len; i++) val[i]=read();
- DA(S,SA,len+,); calheight(S,SA,len);
- init();
- work();
- for (int i=; i<len; i++)
- printf("%lld %lld\n",ans1[i],ans2[i]);
- return ;
- }
感觉自己shi过了一道好题QAQ,以后再回来自己从头搞一遍...
【BZOJ-4199】品酒大会 后缀数组 + 并查集合并集合的更多相关文章
- NOI 2015 品酒大会 (后缀数组+并查集)
题目大意:略 40分暴力还是很好写的,差分再跑个后缀和 和 后缀最大值就行了 一种正解是后缀数组+并查集 但据说还有后缀数组+单调栈的高端操作蒟蒻的我当然不会 后缀数组求出height,然后从大到小排 ...
- BZOJ 4199: [Noi2015]品酒大会( 后缀数组 + 并查集 )
求出后缀数组后, 对height排序, 从大到小来处理(r相似必定是0~r-1相似), 并查集维护. 复杂度O(NlogN + Nalpha(N)) ------------------------- ...
- [UOJ#131][BZOJ4199][NOI2015]品酒大会 后缀数组 + 并查集
[UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...
- 【BZOJ4199】[Noi2015]品酒大会 后缀数组+并查集
[BZOJ4199][Noi2015]品酒大会 题面:http://www.lydsy.com/JudgeOnline/wttl/thread.php?tid=2144 题解:听说能用SAM?SA默默 ...
- [NOI2015] 品酒大会 - 后缀数组,并查集,STL,启发式合并
[NOI2015] 品酒大会 Description 对于每一个 \(i \in [0,n)\) 求有多少对后缀满足 LCP 长度 \(\le i\) ,并求满足条件的两个后缀权值乘积的最大值. So ...
- 【学术篇】NOI2015 品酒大会 后缀数组+并查集
省选前大致是刷不了几道题了... 所以就找一些裸一点的题目练练板子算了= = 然而这题一点都不裸, 也并不怎么好写... 于是就浪费了将近一下午的时间... 然而还不是因为后缀数组板子不熟= = 首先 ...
- Uoj #131. 【NOI2015】品酒大会 后缀数组,并查集
#131. [NOI2015]品酒大会 统计 描述 提交 自定义测试 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项, ...
- BZOJ 4199: [Noi2015]品酒大会 [后缀数组 带权并查集]
4199: [Noi2015]品酒大会 UOJ:http://uoj.ac/problem/131 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 ...
- BZOJ.4199.[NOI2015]品酒大会(后缀数组 单调栈)
BZOJ 洛谷 后缀自动机做法. 洛谷上SAM比SA慢...BZOJ SAM却能快近一倍... 显然只需要考虑极长的相同子串的贡献,然后求后缀和/后缀\(\max\)就可以了. 对于相同子串,我们能想 ...
随机推荐
- GNU Trove trove4j
GNU Trove (http://trove4j.sourceforge.net/) 是一个Java 集合类库.在某些场景下,Trove集合类库提供了更好的性能,而且内存使用更少.以下是Trove中 ...
- usb驱动开发13之设备生命线
上一节勉勉强强把struct urb这个中心给说完,接着看那三个基本点. 第一个基本点,usb_alloc_urb函数,创建urb的专用函数,为一个urb申请内存并做初始化,在drviers/usb/ ...
- indows 8上强制Visual Studio以管理员身份运行
http://diaosbook.com/Post/2013/2/28/force-visual-studio-always-run-as-admin-on-windows-8 Windows 8的一 ...
- java 实现从15位~18位的身份证号码转换,校验中国大陆公民身份证、香港居民身份证、澳门身份证和台湾身份证。
package xidian.sl.netcredit.util; /** * Copyright (C) 2009-2010 Yichuan, Fuchun All rights reserved. ...
- beaglebone_black_学习笔记——(9)UART使用
笔者通过查阅相关资料,了解了BeagleBoneBlack开发板的UART接口特性,掌握的UART接口的基本使用方法,最后通过一个C语言的例程实现串口的自发自收.有了这个串口开发板就可和其他设备进行串 ...
- FineUI v4.0.3 (beta) 和 FineUI v3.3.3 发布了!
关于FineUI基于 ExtJS 的开源 ASP.NET 控件库 FineUI的使命创建 No JavaScript,No CSS,No UpdatePanel,No ViewState,No Web ...
- WPF循环加载图片导致内存溢出的解决办法
程序场景:一系列的图片,从第一张到最后一张依次加载图片,形成“动画”. 生成BitmapImage的方法有多种: 1. var source=new BitmapImage(new Uri(" ...
- ASP.NET Web API 安全验证之摘要(Digest)认证
在基本认证的方式中,主要的安全问题来自于用户信息的明文传输,而在摘要认证中,主要通过一些手段避免了此问题,大大增加了安全性. 1.客户端匿名的方式请求 (无认证) HTTP/ Unauthorized ...
- 基于FPGA的通信信号源的设计
通信信号源设计原理 通过设计一个DDS信号源,然后将该信号作为载波信号,再对基带信号进行2ASK.2FSK.2PSK.2DPSK调制,进而产生多种通信信号. 设计框图如下: 将PN序列进行2ASK.2 ...
- 准确率(Accuracy), 精确率(Precision), 召回率(Recall)和F1-Measure
yu Code 15 Comments 机器学习(ML),自然语言处理(NLP),信息检索(IR)等领域,评估(Evaluation)是一个必要的 工作,而其评价指标往往有如下几点:准确率(Accu ...