【学术篇】NOI2015 品酒大会 后缀数组+并查集
省选前大致是刷不了几道题了... 所以就找一些裸一点的题目练练板子算了= =
然而这题一点都不裸, 也并不怎么好写... 于是就浪费了将近一下午的时间... 然而还不是因为后缀数组板子不熟= =
首先这个"r相似"很显然就是lcp的值, 也就能想到后缀数组上的height... 不会后缀数组的先左转百度~
那么我们考虑如果有一个连续的区间, 它们的height值都是大于等于r的, 那么这段区间中的后缀两两"r相似".
而"r相似"的话, 也肯定有"r-1相似", "r-2相似", ... "0相似". 这样我们就会重复统计, 就会浪费时间. 所以我们不妨将这个连续的区间表示成一个点, 并查集!!
这样我们把id按照对应位置的height降序排序, 然后对于每个id, 我们把id-1这个点所在的区间和id所在的区间合并(根据height的含义, 就是表示sa[id]和sa[id-1]所对应的后缀的lcp长度..)
合并的同时维护信息即可. 说起来挺轻巧的, 其实不是很好懂.. (当然也可能是我太蒻了 理解能力差)
最后不要忘了统计的时候做一个后缀和, 比r大的答案都要统计一下.
说的很不清楚(然而其实只是用来练板子谁曾想到这破题我写了一下午呢...)
有不懂的可以去看代码看了就更不懂了Emmmm
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=300050;
const long long INF=1ll<<62;
char s[N];
int fa[N],sz[N],mn[N],mx[N],w[N],id[N];
long long cnt[N],ans[N];
int x[N],y[N],sa[N],rnk[N],cc[N],height[N],len;
inline int gn(int a=0,char c=0,int f=1){
for(;(c<'0'||c>'9')&&c!='-';c=getchar());
if(c=='-') c=getchar(),f=-1;
for(;c>47&&c<58;c=getchar()) a=a*10+c-48;
return a*f;}
bool hcmp(int x,int y){
if(height[x]==height[y]) return x<y;
return height[x]>height[y];
}
bool cmp(int *y,int a,int b,int k){
int ra=a+k>=len?-1:y[a+k],rb=b+k>=len?-1:y[b+k];
return y[a]==y[b]&&ra==rb;
}
void make_sa(){ int m=26;
for(int i=0;i<m;++i) cc[i]=0;
for(int i=0;i<len;++i) ++cc[x[i]=s[i]-'a'];
for(int i=1;i<m;++i) cc[i]+=cc[i-1];
for(int i=len-1;i>=0;--i) sa[--cc[x[i]]]=i;
for(int k=1;k<=len;k<<=1){ int p=0;
for(int i=len-k;i<len;++i) y[p++]=i;
for(int i=0;i<len;++i) if(sa[i]>=k) y[p++]=sa[i]-k;
for(int i=0;i<m;++i) cc[i]=0;
for(int i=0;i<len;++i) ++cc[x[y[i]]];
for(int i=1;i<m;++i) cc[i]+=cc[i-1];
for(int i=len-1;i>=0;--i) sa[--cc[x[y[i]]]]=y[i];
std::swap(x,y); m=1; x[sa[0]]=0;
for(int i=1;i<len;++i)
x[sa[i]]=cmp(y,sa[i],sa[i-1],k)?m-1:m++;
if(m>=len) break;
}
for(int i=0;i<len;++i) rnk[sa[i]]=i;
}
void make_height(){ int k=0;
for(int i=0;i<len;++i){
if(!rnk[i]) continue;
int j=sa[rnk[i]-1];
if(k) --k;
while(s[i+k]==s[j+k]) ++k;
height[rnk[i]]=k;
}
}
int find(int x){ if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x];}
void merge(int x,int y){
sz[y]+=sz[x]; fa[x]=y;
mn[y]=min(mn[x],mn[y]);
mx[y]=max(mx[x],mx[y]);
}
int main(){
len=gn();
scanf("%s",s); len=strlen(s);
make_sa(); make_height();
for(int i=0;i<len;++i)
w[i]=gn();
for(int i=0;i<len;++i){
fa[i]=i; id[i]=i;
mx[i]=w[sa[i]]; mn[i]=w[sa[i]];
sz[i]=1; ans[i]=-INF;
} ::sort(id+1, id+len, hcmp);
for(int i=1;i<len;++i){
int x=find(id[i]-1),y=find(id[i]);
cnt[height[id[i]]]+=1ll*sz[x]*sz[y];
ans[height[id[i]]]=max(ans[height[id[i]]],1ll*mn[x]*mn[y]);
ans[height[id[i]]]=max(ans[height[id[i]]],1ll*mn[x]*mx[y]);
ans[height[id[i]]]=max(ans[height[id[i]]],1ll*mx[x]*mn[y]);
ans[height[id[i]]]=max(ans[height[id[i]]],1ll*mx[x]*mx[y]);
merge(x,y);
}
for(int i=len-2;i>=0;--i)
cnt[i]+=cnt[i+1],ans[i]=max(ans[i],ans[i+1]);
for(int i=0;i<len;++i)
printf("%lld %lld\n",cnt[i],cnt[i]?ans[i]:0);
}
【学术篇】NOI2015 品酒大会 后缀数组+并查集的更多相关文章
- [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 ...
- BZOJ 4199: [Noi2015]品酒大会( 后缀数组 + 并查集 )
求出后缀数组后, 对height排序, 从大到小来处理(r相似必定是0~r-1相似), 并查集维护. 复杂度O(NlogN + Nalpha(N)) ------------------------- ...
- NOI 2015 品酒大会 (后缀数组+并查集)
题目大意:略 40分暴力还是很好写的,差分再跑个后缀和 和 后缀最大值就行了 一种正解是后缀数组+并查集 但据说还有后缀数组+单调栈的高端操作蒟蒻的我当然不会 后缀数组求出height,然后从大到小排 ...
- Uoj #131. 【NOI2015】品酒大会 后缀数组,并查集
#131. [NOI2015]品酒大会 统计 描述 提交 自定义测试 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项, ...
- BZOJ 4199: [Noi2015]品酒大会 [后缀数组 带权并查集]
4199: [Noi2015]品酒大会 UOJ:http://uoj.ac/problem/131 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 ...
- 【BZOJ-4199】品酒大会 后缀数组 + 并查集合并集合
4199: [Noi2015]品酒大会 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 436 Solved: 243[Submit][Status] ...
- BZOJ.4199.[NOI2015]品酒大会(后缀数组 单调栈)
BZOJ 洛谷 后缀自动机做法. 洛谷上SAM比SA慢...BZOJ SAM却能快近一倍... 显然只需要考虑极长的相同子串的贡献,然后求后缀和/后缀\(\max\)就可以了. 对于相同子串,我们能想 ...
随机推荐
- #Ubuntu16.0.4 LTS 安装RabbitMQ
1.ubuntu下安装配置rabbitmq-server服务器环境:ubuntu16.0.4(向下兼容14.0.4)软件版本:RabbitMQ 3.7.5 .Erlang 20.1.7参考文档:htt ...
- 简单递归____Fibonacci数列
#include <stdio.h> int fun(int x) { ||x==) ; else return fun(x-1)+fun(x-2); } int main() { int ...
- python中二维数组的建立,输入和输出
''' for循环: for i in range(x,y,dir): pass 首先这个区间是左闭右开 其次dir在省略的情况下默认为1,就是每次加一,也可以指定 python的数组: python ...
- Vue开发环境的搭建及基本开发流程
1.下载并安装node,下载地址. 2.命令行运行以下命令安装npm淘宝镜像; npm install -g cnpm --registry=https://registry.npm.taobao.o ...
- SQL Server 2014 安装说明
SQL Server 2014 安装说明 本节内容将说明如何通过安装向导在 Windows Server 2012 R2 上安装 SQL Server 2014. 先从 MSDN 网站上下载安装了 S ...
- 【集群】Redis哨兵(Sentinel)模式
主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用.这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式. 一.哨兵 ...
- 大碗宽面Alpha冲刺阶段博客目录
大碗宽面Alpha冲刺阶段博客目录 一.Scrum Meeting 1. [第六周会议记录]第六周链接 2. [第七周会议记录]第七周链接 二.测试报告 [alpha阶段测试报告](博客链接) ## ...
- mysql5.6配置-my
# mkdir -p /home/mysql/3306/{data,binlog,logs} [client] port = socket=/tmp/my3306.sock [mysql] no-au ...
- 【Java架构:基础技术】一篇文章搞掂:MyBatis
本文篇幅较长,建议合理利用右上角目录进行查看(如果没有目录请刷新). 本文主要总结于刘增辉的<MyBatisc从入门到精通>一书,有兴趣的朋友可以自行研读 建议仔细研读官方文档: http ...
- windows环境下安装pymysql(操作带图)
在windows环境下安装pymysql,首先要找到python的安装位置,如果在c盘,启动cmd的时候,要获取管理员权限. 具体步骤,一,管理员模式启动cmd.在箭头指定位置,搜索cmd,出现快捷方 ...