Gym - 102028H Can You Solve the Harder Problem? (后缀数组+RMQ+单调栈)
题意:求一个序列中本质不同的连续子序列的最大值之和。
由于要求“本质不同”,所以后缀数组就派上用场了,可以从小到大枚举每个后缀,对于每个sa[i],从sa[i]+ht[i]开始枚举(ht[0]=0),这样就能不重复不遗漏地枚举出每一个子串。
但是这样做,最坏情况仍旧是$O(n^2)$的,可能会被卡掉,需要进一步优化。
对于每个sa[i],设k=sa[i]+ht[i],则问题转化成了求max(s[sa[i]],s[sa[i]+1],...,s[k])+max(s[sa[i]],s[sa[i]+1],...,s[k+1])+...+max(s[sa[i]],s[sa[i]+1],...,s[n-1])。
可以发现,随着下标的增大,最大值是单调不减的,这启示我们利用单调栈将后缀进行分段,对于每个最大值不同的段求出后缀和,对于每个sa[i],利用RMQ求出s[sa[i],k]中的最大值mx,然后在单调栈上二分找到第一个大于mx的值的下标,将贡献分成左右两部分相加即可。
一开始可以将初始序列离散化,求出后缀数组后再还原回去,这样复杂度就不依赖于序列元素的大小而只与序列长度有关了,$O(nlogn)$
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+,inf=0x3f3f3f3f;
int s[N],buf1[N],buf2[N],b[N],nb,c[N],n,sa[N],ht[N],rnk[N],ST[N][],Log[N],sta[N],idx[N],tp;
ll sum[N];
void Sort(int* x,int* y,int m) {
for(int i=; i<m; ++i)c[i]=;
for(int i=; i<n; ++i)++c[x[i]];
for(int i=; i<m; ++i)c[i]+=c[i-];
for(int i=n-; i>=; --i)sa[--c[x[y[i]]]]=y[i];
}
void da(int* s,int n,int m=) {
int *x=buf1,*y=buf2;
x[n]=y[n]=-;
for(int i=; i<n; ++i)x[i]=s[i],y[i]=i;
Sort(x,y,m);
for(int k=; k<n; k<<=) {
int p=;
for(int i=n-k; i<n; ++i)y[p++]=i;
for(int i=; i<n; ++i)if(sa[i]>=k)y[p++]=sa[i]-k;
Sort(x,y,m),p=,y[sa[]]=;
for(int i=; i<n; ++i)y[sa[i]]=x[sa[i-]]==x[sa[i]]&&x[sa[i-]+k]==x[sa[i]+k]?p-:p++;
if(p==n)break;
swap(x,y),m=p;
}
}
void getht() {
for(int i=; i<n; ++i)rnk[sa[i]]=i;
ht[]=,s[n]=-;
for(int i=,k=; i<n; ++i) {
if(k)--k;
if(!rnk[i])continue;
for(; s[i+k]==s[sa[rnk[i]-]+k]; ++k);
ht[rnk[i]]=k;
}
}
void build() {
for(int i=; i<n; ++i)ST[i][]=s[i];
for(int k=; k<=Log[n]; ++k)
for(int i=; i+(<<k)-<n; ++i)
ST[i][k]=max(ST[i][k-],ST[i+(<<(k-))][k-]);
}
int qry(int L,int R) {
int k=Log[R-L+];
return max(ST[L][k],ST[R-(<<k)+][k]);
}
struct QR {
int k,mx;
bool operator<(const QR& b)const {return k<b.k;}
} qr[N];
void push(int x,int i) {
for(; ~tp&&x>=sta[tp]; --tp);
sta[++tp]=x,sum[tp]=(ll)x*(idx[tp-]-i)+sum[tp-],idx[tp]=i;
}
int main() {
Log[]=-;
for(int i=; i<N; ++i)Log[i]=Log[i>>]+;
int T;
for(scanf("%d",&T); T--;) {
scanf("%d",&n);
for(int i=; i<n; ++i)scanf("%d",&s[i]);
nb=;
for(int i=; i<n; ++i)b[nb++]=s[i];
sort(b,b+nb),nb=unique(b,b+nb)-b;
for(int i=; i<n; ++i)s[i]=lower_bound(b,b+nb,s[i])-b;
da(s,n,n+),getht();
for(int i=; i<n; ++i)s[i]=b[s[i]];
build();
ll ans=;
for(int i=; i<n; ++i) {
int k=sa[i]+ht[i];
qr[i]= {k,qry(sa[i],k)};
}
sort(qr,qr+n);
sta[tp=]=inf,sum[tp]=,idx[tp]=n;
for(int i=n-,j=n-; i>=; --i) {
int k=qr[i].k,mx=qr[i].mx;
for(; j>=k; --j)push(s[j],j);
int t=lower_bound(sta,sta+tp+,mx,greater<int>())-sta-;
ans+=(ll)mx*(idx[t]-k)+sum[t];
}
printf("%lld\n",ans);
}
return ;
}
Gym - 102028H Can You Solve the Harder Problem? (后缀数组+RMQ+单调栈)的更多相关文章
- HDU - 5008 Boring String Problem (后缀数组+二分法+RMQ)
Problem Description In this problem, you are given a string s and q queries. For each query, you sho ...
- HDU 5008 Boring String Problem(后缀数组+二分)
题目链接 思路 想到了,但是木写对啊....代码 各种bug,写的乱死了.... 输出最靠前的,比较折腾... #include <cstdio> #include <cstring ...
- HDU5008 Boring String Problem(后缀数组)
练习一下字符串,做一下这道题. 首先是关于一个字符串有多少不同子串的问题,串由小到大排起序来应该是按照sa[i]的顺序排出来的产生的. 好像abbacd,排序出来的后缀是这样的 1---abbacd ...
- HDU1086You can Solve a Geometry Problem too(判断线段相交)
You can Solve a Geometry Problem too Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/3 ...
- hdu 1086 You can Solve a Geometry Problem too
You can Solve a Geometry Problem too Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/3 ...
- DFS+剪枝 HDOJ 5323 Solve this interesting problem
题目传送门 /* 题意:告诉一个区间[L,R],问根节点的n是多少 DFS+剪枝:父亲节点有四种情况:[l, r + len],[l, r + len - 1],[l - len, r],[l - l ...
- hdu5323 Solve this interesting problem(爆搜)
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud Solve this interesting problem Time Limit ...
- (hdu step 7.1.2)You can Solve a Geometry Problem too(乞讨n条线段,相交两者之间的段数)
称号: You can Solve a Geometry Problem too Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/ ...
- HDU 1086:You can Solve a Geometry Problem too
pid=1086">You can Solve a Geometry Problem too Time Limit: 2000/1000 MS (Java/Others) Mem ...
随机推荐
- [Cometoj#3 B]棋盘_状压dp
棋盘 题目链接:https://cometoj.com/contest/38/problem/B?problem_id=1535 数据范围:略. 题解: 因为行数特别小,所以$dp$的时候可以状压起来 ...
- js 中json遍历 添加 修改 类型转换
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- 将mysql中一行中的几个字段 转换成一列并从其他数据库中查对应的邮件信息
--将项目中的总监,经理,等的邮箱合并为一行 SELECT GROUP_CONCAT(t.USER_EMAIL SEPARATOR ' ') mail_address FROM portal.t_ac ...
- 如何配置kindeditor的工具栏
kindeditor编辑器的工具栏主要是指编辑器输入框上方的那些可以操作的菜单,默认情况下编辑器是给予了所有的工具栏.针对不同的用户,不同的项目,不同的环境,可能就需要保留部分工具栏.那么我们应该如何 ...
- 【hash表】收集雪花
[哈希和哈希表]收集雪花 题目描述 不同的雪花往往有不同的形状.在北方的同学想将雪花收集起来,作为礼物送给在南方的同学们.一共有n个时刻,给出每个时刻下落雪花的形状,用不同的整数表示不同的形状.在收集 ...
- MySQL SELECT语法(四)UNION语法详解
源自MySQL 5.7 官方手册:13.2.9.3 UNION Syntax 一.UNION语法 UNION用于将多个SELECT语句的结果合并到一个结果集中. SELECT ... UNION [A ...
- 进程程序替换(自主实现shell)
进程替换 替换进程所运行的程序 流程:将另一段代码加载到内存中,通过页表将原来进程的映射关系重新建立到新的程序在内存中的地址,相当于替换了进程所运行程序以及所要处理的数据 (替换了代码段,重新初始化数 ...
- 【css】浅谈BFC
定义: 块格式化上下文(Block Formatting Context,BFC) 是Web页面的可视化CSS渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域. BFC的布 ...
- 15 Django之Celery发送邮件
异步任务--celery发送邮件 安装两个python包: pip install celery==3.1.25 pip install django-celery==3.2.1 pip instal ...
- 单变量图形的pandas方法
数据加载与展示: 1. 类别数据的Bar图 1.1 每一类对应有多少个 1.2 每类数量占整体的比值 1.3 对X轴进行排序