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 ...
随机推荐
- 《MIT 6.828 Lab 1 Exercise 10》实验报告
本实验的网站链接:MIT 6.828 Lab 1 Exercise 10. 题目 Exercise 10. To become familiar with the C calling conventi ...
- 《你必须知道的495个C语言问题》读书笔记之第1-2章:声明和初始化
1. C标准中并没有精确定义数值类型的大小,但作了以下约束: (1) char类型可以存放小于等于127的值: (2) short int和int可以存放小于等于32767的值: (3) long i ...
- Win10修改字体
先将自己喜欢的字体下载下来. 把自己喜欢的字体下载之后,一般会是一个压缩包,将其解,格式是ttf. 点击解压后的字体文件,将其安装在windows系统之中. 键盘上先按住win,在按R,出现一个窗口, ...
- 关于MD5加盐使用
md5 是一种数据加密,例子是对123456 进行了两次加盐 第一次是 inputPassToFormPass salt是固定的 1a2b3c4d 第二次是 formPassToDBPass s ...
- PAT题目AC汇总(待补全)
题目AC汇总 甲级AC PAT A1001 A+B Format (20 分) PAT A1002 A+B for Polynomials(25) PAT A1005 Spell It Right ( ...
- Linux/CentOS 配置Mysql-server过程和遇到错误解决方法
第一步:下载mysql-server 方法1.wget url(你所要下载的链接,可以从mysq官网查找)到当前目录下 方法2.到mysql官网下载包之后通过xftp传到linux 第二步:解压tar ...
- 牛客 128A 礼物 (组合计数)
大意: n种一元的奥利奥, m种2元的奥利奥, 求花恰好k元钱购买奥利奥的方案数. 可重组合问题, 直接dp即可. #include <iostream> #include <sst ...
- Spring HttpServletRequest对象的获取
1.Controller方法上获取 @RequestMapping(value = "/aliyun/ccc/callComing", method = RequestMethod ...
- python 画图像训练结果的loss图
得到每个epoch的loss和predict精度后,就可以愉快地画图直观地看出训练结果和收敛性了. # coding:utf-8 import matplotlib.pyplot as plt dat ...
- Python 数字(函数)
Python支持4种不同数值类型: 整型(Int) - 通常被称为是整型或整数,是正或负整数,不带小数点. 长整型(long integers) - 无限大小的整数,整数最后是一个大写或小写的L. 浮 ...