【loj2133】【NOI2015】品酒大会
Solution
虽然说这题貌似用后缀树之类的好像会更加简短一点。。但是还是因为在智力康复所以就还是用后缀数组好了嗯(哇好感动啊难得那么顺畅写了一道noi的题qwq以及为什么我调试的时候调的都是树状数组的部分啊。。)
其实仔细想一下,\(k\)相似的答案对\(x\in [0,k-1]\)相似的答案都是由贡献的,也就是说大概是一个后缀和或者后缀最大值的感觉,所以这里就产生了一个最初步的想法我们也许可以用树状数组来统计答案
然后接着考虑怎么算相似度最大为\(k\)的贡献
其实这题的套路和Portal -->「HAOI2016」找相同字符几乎是。。一样的
同样的我们也是从\(height[i]\)作为区间最小值的贡献这个方向来考虑:我们记\(solve(l,r)\)表示处理\(rk\)值\(\in [l,r]\)的后缀对答案的贡献,然后可以用ST表预处理之后\(O(1)\)求得整一个区间内的\(height\)的最小值\(x\),也就是这整一个区间内的任意两个后缀的\(lcp\)一定满足\(lcp>=x\),即相似值一定\(>=x\)
统计方案数的话,我们就直接找到这个最小值的位置\(mid\),往树状数组中\(x\)的位置丢入\(((mid-1)-l+1)*(r-mid+1)\)即可(就是在\([l,mid-1]\)中选一个,在\([mid,r]\)中选一个)
统计美味度的最大值的话,我们也是可以用ST表预处理出\(rk\)值\(\in [l,r]\)的后缀开头位置的美味度最大值和最小值,然后查询区间\([l,mid-1]\)中的最大值最小值(记为\(recl.fir\)和\(recl.sec\)),以及区间\([mid,r]\)中的最大值最小值(记为\(recr.fir\)和\(recr.sec\)),然后往记录最大值的树状数组中\(x\)的位置丢入\(max(recl.fir*recr.fir,recl.sec*recr.sec)\)即可
稍微说明一下需要记录最大和最小值的原因是这里的美味度可能是负数
然后处理完当前区间之后我们再递归处理\([l,mid-1]\)和\([mid,r]\)就好了(同样的这里的区间的开闭之类的也是可以根据个人喜好自己更改的反正。。上面查询什么的跟递归处理的一致就好了)
然后最后直接对于每一个不同的相似度在两个树状数组中分别\(log\)的时间查询一下就好了
最后有一个小细节:在ST表查询\(height\)最小值的时候,因为我们\(height\)的定义是与前一个相邻的后缀的\(lcp\),所以查询的下界需要\(+1\),而查询美味度最大值的时候并不需要,如果这两个查询放在一起写的话(比如说。。我这种写法qwq),要稍微注意一下
代码大概长这个样子
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define Pr pair<int,int>
#define mp make_pair
#define ll long long
using namespace std;
const int N=3*(1e5)+10,TOP=20;
const ll inf=(1e18)+10;
char s[N];
ll V[N],lis[N],a[N];
int n,m;
bool cmp(int x,int y){return x>y;}
struct Data{/*{{{*/
ll fir,sec;
Data(){}
Data(ll fir1,ll sec1) {fir=fir1; sec=sec1;}
friend Data update(Data x,Data y){
static ll tmp[4];
tmp[0]=x.fir; tmp[1]=x.sec; tmp[2]=y.fir; tmp[3]=y.sec;
sort(tmp,tmp+4,cmp);
x.fir=tmp[0]; x.sec=tmp[3];
return x;
}
};/*}}}*/
namespace Bit_sum{/*{{{*/
ll c[N];
int mx;
void init(int _mx){
mx=_mx;
for (int i=0;i<=mx;++i) c[i]=0;
}
void insert(int x,ll delta){
for (;x;x-=x&-x) c[x]+=delta;
}
ll query(int x){
ll ret=0;
for (;x<=mx;x+=x&-x) ret+=c[x];
return ret;
}
}/*}}}*/
namespace Bit_mx{/*{{{*/
ll c[N];
int mx;
void init(int _mx){
mx=_mx;
for (int i=0;i<=mx;++i) c[i]=-inf;
}
void insert(int x,ll delta){
for (;x;x-=x&-x) c[x]=max(c[x],delta);
}
ll query(int x){
ll ret=-inf;
for (;x<=mx;x+=x&-x) ret=max(ret,c[x]);
return ret==-inf?0:ret;
}
}/*}}}*/
namespace Sa{/*{{{*/
int a[N],b[N],c[N],sa[N],height[N],rk[N];
int mn[N][TOP+1],loc[N][TOP+1];
Data val[N][TOP+1];
int mx;
bool cmp(int x,int y,int len,int *r)
{return r[x]==r[y]&&r[x+len]==r[y+len];}
void Sort(int n){
for (int i=0;i<=mx;++i) c[i]=0;
for (int i=1;i<=n;++i) ++c[a[b[i]]];
for (int i=1;i<=mx;++i) c[i]+=c[i-1];
for (int i=n;i>=1;--i) sa[c[a[b[i]]]--]=b[i];
}
void get_sa(int n){
mx=0;
for (int i=1;i<=n;++i) a[i]=s[i]-'a'+1,b[i]=i,mx=max(mx,a[i]);
int cnt=0;
Sort(n);
for (int len=1;cnt<n;len<<=1){
cnt=0;
for (int i=n-len+1;i<=n;++i) b[++cnt]=i;
for (int i=1;i<=n;++i)
if (sa[i]>len)
b[++cnt]=sa[i]-len;
Sort(n);
swap(a,b);
cnt=1; a[sa[1]]=1;
for (int i=2;i<=n;a[sa[i++]]=cnt)
if (!cmp(sa[i],sa[i-1],len,b)) ++cnt;
mx=cnt;
}
}
void rmq(){
for (int i=1;i<=n;++i){
mn[i][0]=height[i],loc[i][0]=i;
val[i][0]=Data(V[sa[i]],V[sa[i]]);
}
for (int j=1;j<=TOP;++j)
for (int i=n-(1<<j)+1;i>=1;--i){
if (mn[i][j-1]<mn[i+(1<<j-1)][j-1]){
mn[i][j]=mn[i][j-1],loc[i][j]=loc[i][j-1];
}
else{
mn[i][j]=mn[i+(1<<j-1)][j-1],loc[i][j]=loc[i+(1<<j-1)][j-1];
}
val[i][j]=update(val[i][j-1],val[i+(1<<j-1)][j-1]);
}
}
void get_height(int n){
for (int i=1;i<=n;++i) rk[sa[i]]=i;
int k=0;
for (int i=1;i<=n;++i){
if (k) --k;
while (s[i+k]==s[sa[rk[i]-1]+k]) ++k;
height[rk[i]]=k;
}
rmq();
}
Pr get_lcp(int x,int y,Data &ret){//ranks
if (x==y){
ret=val[x][0];
return mp(n-sa[x]+1,x);
}
if (x>y) swap(x,y);
++x;
int len=y-x+1,lg=(int)(log(1.0*len)/log(2.0)),lg1=(int)(log(1.0*(len+1))/log(2.0));
ret=update(val[x-1][lg1],val[y-(1<<lg1)+1][lg1]);
if (mn[x][lg]<mn[y-(1<<lg)+1][lg])
return mp(mn[x][lg],loc[x][lg]);
else
return mp(mn[y-(1<<lg)+1][lg],loc[y-(1<<lg)+1][lg]);
}
void solve(int l,int r){
if (l>=r) return;
Data recl,recr;
Pr tmp=get_lcp(l,r,recl);
int lcp=tmp.first,mid=tmp.second;
get_lcp(l,mid-1,recl);
get_lcp(mid,r,recr);
Bit_mx::insert(lcp+1,max(recl.fir*recr.fir,recl.sec*recr.sec));
Bit_sum::insert(lcp+1,1LL*(mid-1-l+1)*(r-mid+1));
solve(l,mid-1);
solve(mid,r);
}
}/*}}}*/
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
scanf("%d",&n);
scanf("%s",s+1);
for (int i=1;i<=n;++i) scanf("%lld",V+i);
Sa::get_sa(n);
Sa::get_height(n);
Data ttmp;
Bit_mx::init(n); Bit_sum::init(n);
Sa::solve(1,n);
for (int i=1;i<=n;++i)
printf("%lld %lld\n",Bit_sum::query(i),Bit_mx::query(i));
}
【loj2133】【NOI2015】品酒大会的更多相关文章
- BZOJ 4199: [Noi2015]品酒大会 [后缀数组 带权并查集]
4199: [Noi2015]品酒大会 UOJ:http://uoj.ac/problem/131 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 ...
- [UOJ#131][BZOJ4199][NOI2015]品酒大会 后缀数组 + 并查集
[UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...
- 洛谷 P2178 [NOI2015]品酒大会 解题报告
P2178 [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 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 酒家”和“首席 ...
- [NOI2015]品酒大会(SA数组)
[NOI2015]品酒大会 题目描述 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战 两个环节,分别向优胜者颁发"首席品酒家"和" ...
- 洛谷P2178 [NOI2015]品酒大会 后缀数组+单调栈
P2178 [NOI2015]品酒大会 题目链接 https://www.luogu.org/problemnew/show/P2178 题目描述 一年一度的"幻影阁夏日品酒大会" ...
- [NOI2015] 品酒大会 - 后缀数组,并查集,STL,启发式合并
[NOI2015] 品酒大会 Description 对于每一个 \(i \in [0,n)\) 求有多少对后缀满足 LCP 长度 \(\le i\) ,并求满足条件的两个后缀权值乘积的最大值. So ...
- [BZOJ4199][NOI2015]品酒大会
#131. [NOI2015]品酒大会 统计 描述 提交 自定义测试 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项, ...
随机推荐
- Java 分割、合并byte数组
场景:上传文件较大,把存放文件内容byte数组拆分成小的.下载的时候按照顺序合并. 起初觉得挺麻烦的,写完觉得挺简单. 切割: /** * 拆分byte数组 * * @param bytes * 要拆 ...
- 获取Java线程返回值的几种方式
在实际开发过程中,我们有时候会遇到主线程调用子线程,要等待子线程返回的结果来进行下一步动作的业务. 那么怎么获取子线程返回的值呢,我这里总结了三种方式: 主线程等待. Join方法等待. 实现Call ...
- 爬虫2.5-scrapy框架-下载中间件
目录 scrapy框架-下载中间件 scrapy框架-下载中间件 middlewares.py中有两个类,一个是xxSpiderMiddleware类 一个是xxDownloaderMiddlewar ...
- 136.只出现一次的数字 leetcode ^运算符 JavaScript解法
leetcode上的一道题简单题 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次.找出那个只出现了一次的元素. 说明: 你的算法应该具有线性时间复杂度. 你可以不使用额外空间 ...
- Halcon学习网
重码网是一个在线机器视觉学习网站,推出了Halcon,Visionpro机器视觉学习视频教程,视频内容通俗易懂,没有编程基础的同学,照着视频练习,也同样可以学会. 学机器视觉,拿高薪,成就技术大拿.重 ...
- PowerShell自定义修改远程桌面RDP端口
应朋友的要求写了一个通过PowerShell修改远程桌面(Remote Desktop)端口的脚本,不复杂,启动脚本后有两个选项:1.自定义远程桌面:2.回复远程桌面的默认端口3389 发出来给有用的 ...
- CentOS-6.x系列查看cpu核数
使用CentOS7.x使用习惯了后用top命令,然后按1就可以查看相关的cpu核心数等相关信息 相关概念: 物理CPU:实际Server中插槽上的CPU个数. 物理cpu数量:可以数不重复的 phys ...
- Week4_Linux书本一二两章
第一章的学习内容就是对Linux内核有一个基本的了解,同时知道一些关于Linux的知识. 学习Linux,可以自己有一台装有Linux操作系统的机器,源代码的作用无可替代: Linux发展历程简介:L ...
- 用P4对数据平面进行编程
引言 SDN架构强调了对控制平面的可编程,数据平面只负责转发,导致数据平面很大程度上受制于功能固定的包处理硬件. P4语言的特性: 目标无关性:P4语言不受制于具体设备,所有可编程芯片都可以使用P4编 ...
- Linux安装weblogic
一.软件安装 1. 安装前的准备工作 1.1 首先请确认您要安装的WebLogic版本所在的平台已通过了BEA的认证,完整的认证平台列表请参考 http://e-docs.bea.com/wls/ce ...