题意

如题目的图所示,每行都可以左右移动,但是数字不允许断开,且不许越界(宽度为w)。

单独求每一列的最大的和为多少。

思路

对于每一列来说,在每一行上都有一个可以取到的区间,

所以,对于一列来说,答案就是每行的区间最大值的和。区间最大值可以用RMQ或者单调队列求。

一开始题目看错了,以为是w*n<=1e6,其实是w<=1e6,n<=1e6,Σleni<=1e6(leni为第i行的长度),直接上w*n*log,果断T了。

显然,当leni 比w小很多时,中间会有很多列都可以取到整行的所有数字,所以对于这些列,它们求的区间最大值,其实就是整行的最大值。

对于头尾的一些列,取不到所有数字,那我们就暴力算出它们可以取到的区间,然后查询。

由于w*n<=1e12,而中间那些列查出来的最大值其实是一样的,所以可以用差分。

(一些细节)

有时候查询出来的区间最大值是负数,但是有时候其实可以取到0(移到空格),而有时候只能取负数(移不到空格)。

len <= i <= w - len + 1 符合条件的第i列可以取到整行

当整行都为负数时,

有时候第len列和第(w-len+1)列只能取负数,

但是,第len+1列和第(w-len+1 - 1)列一定可以取到空格,也就是0

所以,我们把第len列和第(w-len+1)列,归为暴力算的部分,因为暴力算的时候,都有特判是否可以取0。

这样,中间的那些就可以直接max(0,rmq(1,len))了

代码(RMQ)

(我的姿势比较差,代码又长,跑的还慢,跑了700+ms)

#include <stdio.h>
#include <queue>
#include <string>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <set>
using namespace std;
typedef long long int ll;
const int maxn = 1e6 + ;
const int inf = ;
const ll mod = ;
const ll seed = ;
int st[maxn][],mm[maxn],b[maxn];
void initRMQ(int n)
{
mm[] = -;
for(int i = ;i <= n;i++){
mm[i] = ((i & (i - )) == ) ? mm[i - ] + :mm[i - ];
st[i][] = b[i];
}
for(int j = ;j <= mm[n];j++){
for(int i = ;i + ( << j) - <= n;i++){
st[i][j] = max(st[i][j - ],st[i + ( << (j - ))][j - ]);
}
}
}
int rmq(int x,int y)
{
int k = mm[y - x + ];
return max(st[x][k],st[y - ( << k) + ][k]);
}
ll ans[maxn];
int main()
{
int n,w,len,l,r;
ll temp;
while(scanf("%d%d",&n,&w) != EOF){
memset(ans,,sizeof(ans));
while(n--){
scanf("%d",&len);
for(int i = ;i <= len;i++){
scanf("%d",&b[i]);
}
initRMQ(len); //i <= w - len + 1
//i >= len
//len <= i <= w - len + 1 符合条件的第i列可以取到整行
int cnt = w,flag = ; //中间
if(len + <= w - len + - ){
temp = max((ll)rmq(,len),(ll));
ans[len + ] += temp;
ans[w - len + ] -= temp;
cnt = len;
flag = ;
} //头
for(int i = ;i <= cnt;i++){
if(len >= i)
r = i;
else
r = len;
if(w - len < i)//w-len+l=i
l = i - (w - len);
else
l = ; temp = rmq(l,r);
if(temp < ){
if(len < i || (w - len) >= i)
temp = ;
}
ans[i] += temp;
ans[i + ] -= temp;
} //尾
if(!flag)
cnt = len;
else
cnt = ;
for(int i = w - len + + cnt;i <= w;i++){
if(len >= i)
r = i;
else
r = len;
if(w - len < i)//w-len+l=i
l = i - (w - len);
else
l = ; temp = rmq(l,r);
if(temp < ){
if(len < i || (w - len) >= i)
temp = ;
}
ans[i] += temp;
ans[i + ] -= temp;
}
} for(int i = ;i <= w;i++){
ans[i] += ans[i - ];
printf("%lld ",ans[i]);
}
puts("");
}
return ;
}

代码(单调队列)

很久没写了,正好复习一下。

单调队列O(n),RMQ O(nlogn),还以为会快一些,但是也一样跑了700+ms

#include <stdio.h>
#include <queue>
#include <string>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <set>
using namespace std;
typedef long long int ll;
const int maxn = 1e6 + ;
const int inf = ;
const ll mod = ;
const ll seed = ;
int qu[maxn],b[maxn];//qu存下标
ll ans[maxn];
int main()
{
int n,w,len,l,r;
ll temp,mx;
while(scanf("%d%d",&n,&w) != EOF){
memset(ans,,sizeof(ans));
while(n--){
mx = ;
scanf("%d",&len);
for(int i = ;i <= len;i++){
scanf("%d",&b[i]);
mx = max(mx,(ll)b[i]);
} //i <= w - len + 1
//i >= len
//len <= i <= w - len + 1 符合条件的第i列可以取到整行
int cnt = len,flag = ; //中间
if(len + <= w - len + - ){
ans[len + ] += mx;
ans[w - len + ] -= mx;
flag = ;
} //头
int head = ,tail = -;
for(int i = ;i <= cnt;i++){
while(head <= tail && b[qu[tail]] <= b[i])
tail--;
qu[++tail] = i;
while(qu[head] < i - (w - len))
head++; temp = b[qu[head]];
if(temp < ){
if(len < i || (w - len) >= i)
temp = ;
}
ans[i] += temp;
ans[i + ] -= temp;
} //尾
if(!flag)
cnt = len + ;
else
cnt = w - len + ;
head = ;tail = -;
for(int i = w;i >= cnt;i--){
int pos = i - (w - len);
while(head <= tail && b[qu[tail]] <= b[pos])
tail--;
qu[++tail] = pos;
while(qu[head] > pos + (w - len))
head++; temp = b[qu[head]];
if(temp < ){
if(len < i || (w - len) >= i)
temp = ;
}
ans[i] += temp;
ans[i + ] -= temp;
}
} for(int i = ;i <= w;i++){
ans[i] += ans[i - ];
printf("%lld ",ans[i]);
}
puts("");
}
return ;
}

cf1208 E Let Them Slide(差分+RMQ\单调队列)的更多相关文章

  1. 树形DP+RMQ+单调队列(Bob’s Race HDU4123)

    题意:有n个房子,这些房子被n-1条道路连接,有一些运动员从一个房子为起点尽可能跑最远的距离且不能通过一条道路超过两次,这些运行员不能选择同样的起点,这些运动员跑的最远距离和最近距离的差值不能超过Q, ...

  2. PKU 2823 Sliding Window(线段树||RMQ||单调队列)

    题目大意:原题链接(定长区间求最值) 给定长为n的数组,求出每k个数之间的最小/大值. 解法一:线段树 segtree节点存储区间的最小/大值 Query_min(int p,int l,int r, ...

  3. ACM学习历程—HDU 5289 Assignment(线段树 || RMQ || 单调队列)

    Problem Description Tom owns a company and he is the boss. There are n staffs which are numbered fro ...

  4. 两种解法-树形dp+二分+单调队列(或RMQ)-hdu-4123-Bob’s Race

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4123 题目大意: 给一棵树,n个节点,每条边有个权值,从每个点i出发有个不经过自己走过的点的最远距离 ...

  5. 模板 RMQ问题ST表实现/单调队列

    RMQ (Range Minimum/Maximum Query)问题是指: 对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j里的最小(大)值,R ...

  6. HDU - 5289 Assignment (RMQ+二分)(单调队列)

    题目链接: Assignment  题意: 给出一个数列,问其中存在多少连续子序列,使得子序列的最大值-最小值<k. 题解: RMQ先处理出每个区间的最大值和最小值(复杂度为:n×logn),相 ...

  7. HDU 5289 Assignment(多校2015 RMQ 单调(双端)队列)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5289 Problem Description Tom owns a company and he is ...

  8. HDU - 5289:Assignment(单调队列||二分+RMQ||二分+线段树)

    Tom owns a company and he is the boss. There are n staffs which are numbered from 1 to n in this com ...

  9. 大视野 1012: [JSOI2008]最大数maxnumber(线段树/ 树状数组/ 单调队列/ 单调栈/ rmq)

    1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 9851  Solved: 4318[Submi ...

随机推荐

  1. java 寒假作业

    寒假作业 现在小学的数学题目也不是那么好玩的. 看看这个寒假作业: □ + □ = □ □ - □ = □ □ × □ = □ □ ÷ □ = □ (如果显示不出来,可以参见[图1.jpg]) 每个方 ...

  2. 强制找回GitLab管理员账户密码的方法

    为了开发运维工具,我们采用自行搭建的GitLab来管理所有代码.悲催的是最近忘记了管理员账户的密码,而且没有邮件服务器,因此无法接收密码找回的邮件,导致无法新建用户或者项目,这样一来,岂不就成为了一个 ...

  3. 第2节 网站点击流项目(下):6、访客visit分析

    0: jdbc:hive2://node03:10000> select * from ods_click_stream_visit limit 2;+--------------------- ...

  4. Linux下如何查找sqlnet.ora 和listener.ora 和tnsnames.ora 配置文件的目录

    1.首先切换到oracle 用户下 使用env 查看数据库配置文件信息 2.然后找到LD_LIBRARY_PATH=/home/opt/oracle/product/11.2.0.4/db_1 (配置 ...

  5. R分析实现对招聘网站薪资预测分析

    1.首先确定数据分析目标——薪酬受哪些因素影响 确定变量: 因变量:薪资 自变量:(定性)-- 公司类别.公司规模.地区.行业类别.学历要求.软件要求. (定量)-- 经验要求(数值型) 分析目标:建 ...

  6. Linux-hosts

    Linux-hosts hosts文件 /etc/hosts OS hosts (path) 使其生效,命令行执行 Windows (C:\Windows\System32\drivers\etc\h ...

  7. 【LeetCode】寻找右区间

    [问题] 给定一组区间,对于每一个区间 i,检查是否存在一个区间 j,它的起始点大于或等于区间 i 的终点,这可以称为 j 在 i 的“右侧”. 对于任何区间,你需要存储的满足条件的区间 j 的最小索 ...

  8. MinGW下编译curl-7.60.0时, 发生ERROR_FILE_NOT_FOUND undeclared

    在编译curl-7.60.0时, 遇到ERROR_FILE_NOT_FOUND undeclared 这个情况, 就没法编译成功!! 下载了以往的版本, 发现是从curl-7.59.0版本开始才有 t ...

  9. python手动实现深拷贝

    深拷贝是将对象全拷贝,包括嵌套对象 def deepcopy(cls): if isinstance(cls, dict): dct = {} for k, v in cls.items(): dct ...

  10. HTTP和HTTPS的区别及HTTPS加密算法

    一.HTTP和HTTPS的概念              HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传 ...