#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <iostream>
using namespace std;
const int MAX_SIZE = 100010 * 2;
const int INFINITE = 99999999;
int num[MAX_SIZE];
int sum[MAX_SIZE];
int q[MAX_SIZE];
int ind[MAX_SIZE];
int begin;
int end;
/**
Problem: HDU3415-Max sum of max-k sequence 【0.3%达成!】
Thanks to : LPP学长,YL学姐,辛苦了两位= =开化我这种愚人
Reference:http://www.cppblog.com/wuxu/archive/2010/08/24/124575.aspx
Knowledge Point:单调队列
关于单调队列还有一篇好的Reference看,入门级的但是讲的足够详细了。
http://www.docin.com/p-49960245.html 用单调性优化优先队列。
Fucking Misunderstanding:
傻逼错误1:误把sum(i,j)写作了sum(i,j) = sum(i) - sum(j)!实际上这样就把元素j抛出去了,应该是sum(i)-sum(j-1)!
Thought:
【大半夜写的,发现bug欢迎fix。。。拿出证据,而不是“我觉得”三个字儿,谢谢】
好吧,都说过了是单调队列,递增的。
这里就当做对单调队列的一个大summary好了。
所谓单调队列,就是其中的内容是单调的,其中元素对应的数组下标也是单调的。
这里的单调指的不是单调上升就是单调下降。
单调队列的名字中虽然带了队列两个字,但是跟队列还是有区别的,不过也有共同之处。
共同之处就是在头(front)的位置取元素,由于单调性可以保证一类问题在单调队列的头处总有最优解,所以是可以这么做的。
不同之处就是单调队列的头部是可以删除元素的(我习惯用front++来实现),当然,跟队列一样,也可以从尾部添加、删除元素(但是头部不能添加元素哦!)
那么,这道题的解题思路在哪儿呢?
就是将给出数组的A[i]求和,Sum[i]表示从[0,i]区间数组A[]元素的和。
那么,如果求[i,j]区间的和,只要用sum[i] - sum[j-1]就好(因为如果减去的是sum[j]那么会把元素j也减掉。。妈的,误区!)
我们用一个单调队列将sum的序号存储在单调队列数组q[]中,并且保证rear - front <= K,这样的话我们保存的
就是连续个sum数组[]的下标,其中的值[ sum[front] , sum[rear-1] ]为sum[m] ( m属于区间[i,j], j - i <= K )
至于rear为什么要-1,则是因为rear始终指向空的空间用来存储sum的新值,记得么?队列的基本性质。
这样就好办了
我们可以将N个数存储在A[1]->A[N]中,A[0]为0,这样是为了方便计算sum[]
sum的计算是这样的:
for(int i = 1 ; i<= N ; i++)
sum[i] = sum[i-1] + A[i];
记得要把N个数的开头K个数(其实是K-1个……因为 N到N+K-1(包括两端)总共是K个数……虽然相减等于K-1,但是由于包括端点还得+1呢~)
放在A[N+1]到A[N+K]中(哎呀,偷懒,就这么放了,不影响结果!)
sum也要算到sum[N+K-1];
关键代码就在 ↓这里,恶心的地方也在这里
为什么是 sum[i-1] < sum[ q[rear-1] ]呢?sum[ q[rear-1] ]好解释
就是队内队尾元素的sum值嘛,但是为什么要sum[i-1]呢?
答案就是在底下的res = ( sum[i] - sum[ q[front] ] )里面。
而q[rear++]=i-1也提示了我们这一点。
只有在遍历到sum[i]的时候,q[rear]存储的是sum[i-1]的下标,才能根据当前的
sum[i]判断是否取到了最大值。证明见后
for(int i = 1 ; i <= N + K - 1 ; i++ )
{
while(front < rear && sum[i-1] < sum[ q[rear-1] ])
rear--;
q[rear++]=i-1;
if( sum[i] - sum[ q[front] ] > res )
{
begin = q[front] + 1;
end = i;
res = sum[i] - sum[q[front]];
}
}
证明刚才说的那个q[rear++] = i-1;
初始:
如果q[rear++]一直得到执行而从未发生rear--这种事(初始么!)
那么q[rear-1]存储的实际上是sum[i-2]的下标,判断sum[i-2] > sum[i-1]的话
rear--后退,让队尾元素变为sum[i-1]下标,亦即q[rear++] = i - 1,保持了q[]中sum值和下标的单调性。
维持:
rear--得到执行一次之后,rear指向的是sum[i-1]未更新前的最大元素,那么如果我们将sum[i-1]和sum[q[rear]]比较,尾部不断向前移动,就是存储下标对应的元素逐渐减小
也就是rear--,一直找到sum[i-1]比sum[q[rear-1]]要大的时候,我们才q[rear++] = i - 1;
终止:
根据一、二可以知道,这样是始终维护了队列的单调性的。
【耗时两个小时的证明,为毛就把i-1放在q[]而不是i呢?该部分为我一根筋的吐槽,非虐勿看!】
证明如下:
妈的,主要是这里想不明白真他妈讨厌!
想一下我们用单调队列来干毛啊,保证sum[q[front]]是这个区间内从A[1]到该区间开始端点和的最小值啊
这样我们sum[i] - sum[q[front]]才是最优啊。
如果你保存的是i的话,那么就得改成
sum[i]-sum[q[rear-1]]+num[q[rear-1]]是最优才可以。
那怎么改?
那就判断的话。。。
第一、不能跟sum[i]判断,要用(sum[q[rear-1]]-num[q[rear-1]])和sum[i]-num[i]判断
if( front < area && ( sum[i]-num[i] ) < (sum[q[rear-1]] - num[q[rear-1]])
本质上不还是跟放i-1是一样的么!!
sum[i]是用来确定最优解的,如果
sum[i] < sum[q[rear-1]] 判断的话,那么,那得到的是毛啊,你把用来确定最优解的东西用来判断?!
你得在优先队列里得到 i 点之前的 sum[k]( num[1] -> num[k]的和的最小值 ) 从而保证q[front]是最优的啊
这也就是为什么保证q[]里面是单调递增的原因啊,怎么能直接把 i 直接扔进去啊,到了 i 点应该是让 i 点之前的和最小啊
i点是用来转移的!看你自己的WA到死的代码,判断最优解的时候不也是
sum[i] - sum[q[front]] + num[q[front]]么,你把sum[i]用来转移的话,你就不能直接扔i进去啊
那不破坏了整个队列在[j,i-1] (j为起点,j = i - K)的最优状态么。。换言之那TM根本就不是最优状态
为神马破坏最优状态了呢?因为有 while(front < rear && i - q[front] > K ) front++ 这句话撑着啊,你要把sum[i]放进来是不是得丢出去一个
元素啊?而且还是front啊!你把最优的丢出去了啊!
其实也不是最优的,因为从初始化的时候就是错的=。=
总之,如果q[]放i并且还用sum[i]进行转移的话,那每次得到的都TM不是最优的状态,因为第一个元素(front)被扔出去了!
娘希匹的!Q.E.D!
【卧槽,我是不是精分了?】
第二、你的起始点确定累不死你。。。
**/
int solve(int N,int K)
{
int res = -INFINITE;
int front = 0;
int rear = 0;
for(int i = 1 ; i <= N+K-1 ; i++)
{
while(front < rear && i - q[front] > K ) //不用写等号!因为k 不等于0
front++; //保持距离在k
/**
主要就是下面那行代码让我费劲了,果然智商是硬伤
首先,简单的,q[rear-1],取得是队尾元素(rear始终指的是队列中的空地方)
而sum[i-1]的原因则是因为我们要用sum[i]来判断当前队列和是否是最优的!证明在解题报告中给出!
**/
while(front < rear && sum[i-1] < sum[ q[rear-1] ])
rear--;
q[rear++]=i-1;
if( sum[i] - sum[ q[front] ] > res )
{
begin = q[front] + 1;
end = i;
res = sum[i] - sum[q[front]];
}
}
if( end > N )
end = end - N;
return res;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("B:\\acm\\SummerVacation\\DP-II\\F.in","r",stdin);
freopen("B:\\acm\\SummerVacation\\DP-II\\F.out","w",stdout);
#endif
int T,N,K;
while(scanf("%d",&T) != EOF)
{
for(int t = 1 ; t <= T; t++)
{
scanf("%d%d",&N,&K);
num[0] = 0;
sum[0] = 0;
memset(num,0,sizeof(num));
memset(sum,0,sizeof(sum));
memset(q,0,sizeof(q));
memset(ind,0,sizeof(ind));
begin = 0; end = 0;
for(int i = 1 ; i <= N ;i++)
{
scanf("%d",&num[i]);
sum[i] = num[i] + sum[i-1];
}
for(int i = N+1; i <= N+K ; i++)
{
num[i] = num[i-N];
sum[i] = num[i]+sum[i-1];
}
int res = solve(N,K);
printf("%d %d %d\n",res,begin,end);
}
}
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
相关推荐
FPGA 核脉冲梯形成型 Verilog 实现:从 MATLAB 到 50MHz 采样率部署
本文详细解析了FPGA实现核脉冲梯形成型的完整流程,从MATLAB仿真到50MHz采样率的Verilog硬件部署。重点探讨了梯形成型算法对负指数信号的优化处理,包括定点数量化、流水线架构设计及资源优化技巧,为核辐射探测与高能物理实验提供高效解决方案。
循环队列的基本操作(初始化,入队,出队,取队头,遍历输出)
#include<stdio.h> #define MaxSize 5 typedef struct { int data[MaxSize]; int front,rear; }SqQueue; void InitQueue(SqQueue &Q){ Q.front = Q.rear = 0; } //进队 bool EnQueue(SqQueue &Q,int x){ if((Q.rear+1)%MaxSize == Q.front) return false;
【开关电源篇】开关电源——只需这三个阶段,从电源小白到维修大神
🔌 该篇为的原创文章跳转目录,小二持续更新跳转链接,尽情关注!
循环队列
一 循环队列 typedef struct { DATATYPE buf[MAX]; int front; int rear; }LoopQueue; 规定: 1.队空条件 q->front == q->rear; 2.队满条件 (q->rear + 1) % MAX == q->front; 3.front和rear更新原则 q->front = (q->front + 1) % MAX; q->rear = (q->...
大麦APP抢票协议分析:从‘掌密网络’代码看移动端API安全防护
本文深度解析了大麦APP抢票协议的安全防护体系,重点分析了'掌密网络'代码中体现的动态签名、设备指纹和人机验证等关键技术。文章详细介绍了大麦APP如何通过多层次API安全防护应对抢票压力,包括参数加密、请求头部设计和异常处理机制,为移动应用开发者提供了安全实践建议。
ESP32驱动TFT屏幕实战:LVGL与TFT_eSPI完美结合
本文详细介绍了如何在ESP32上结合TFT_eSPI驱动库与LVGL图形库,实现高效、流畅的嵌入式GUI开发。内容涵盖硬件连接、软件环境搭建、库配置、LVGL移植、界面创建及性能优化等全流程实战指南,帮助开发者快速构建低成本、高性能的交互式显示应用。
hdu 3415 Max Sum of Max-K-sub-sequence(单调队列)
Max Sum of Max-K-sub-sequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5385 Accepted Submission(s): 1952 Problem Description
[STM32H750]HAL库下FMC驱动正点原子MCU屏的移植与优化
本文详细介绍了在STM32H750平台上使用HAL库移植与优化正点原子MCU屏幕驱动的完整过程。重点解析了FMC硬件配置、Cache一致性处理、精确延时实现等关键技术难点,提供了实用的移植方案和性能优化技巧,帮助开发者高效解决屏幕显示问题。
HDU 3415 Max Sum of Max-K-sub-sequence
链接:http://acm.hdu.edu.cn/showproblem.php?pid=3415 题意:一个共有N个整数的环形串,计算最多有K个整数的连续子串的和。 分析:单调队列。用sum[i]存储前i个整数的和,则i+1到j之间的整数和就是:sum[j]-sum[i]。对于环形情况的处理,只要在整数串最后补上前K个数就可以对其进行线性串的处理。单调队列的队首存放当前K+1个SUM值的最小
Python爬虫实战:如何优雅地处理BOSS直聘的反爬机制与Cookie失效问题
本文详细介绍了如何通过Python爬虫技术优雅应对BOSS直聘的反爬机制与Cookie失效问题。从多账号轮换、动态请求头生成到代理IP管理,提供了一套完整的解决方案,帮助开发者构建稳定高效的数据采集系统,有效提升爬虫成功率与数据质量。
自定义载板RK3588HDMI输入配置完整解决方案
✅ HDMI输入信号检测✅ 自动时序识别(支持1080p@60Hz等标准格式)✅ V4L2视频设备接口✅ 实时视频流捕获✅ H.264编码录制✅ HDCP内容保护支持问题根因识别:发现了hdmim1模块资源冲突的本质问题硬件设计理解:明确了Orange Pi 5 Plus的真实硬件设计意图功能实现:成功启用HDMI输入功能,替代了无法使用的HDMI1输出完整验证:建立了从硬件检测到视频录制的完整测试流程。
[ACM] hdu 3415 Max Sum of Max-K-sub-sequence (单调队列)
Max Sum of Max-K-sub-sequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5673 Accepted Submission(s): 2049 Problem Description
AutosarMCAL开发——基于EB MCU驱动
本文为博主个人学习总结记录,如有不正,欢迎指正。
HDU 3415 Max Sum of Max-K-sub-sequence【单调队列】
单调队列: 一、 什么是单调(双端)队列 单调队列,顾名思义,就是一个元素单调的队列,那么就能保证队首的元素是最小(最大)的,从而满足动态规划的最优性问题的需求。 单调队列,又名双端队列。双端队列,就是说它不同于一般的队列只能在队首删除、队尾插入,它能够在队首、队尾同时进行删除。 【单调队列的性质】 一般,在动态规划的过程中,单调队列中每个元素一般存储的是两个值: 1、在原数列中的位
Data-Structures-and-Algorithm-Analysis-in-Java.pdf
作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...
Probability and Statistics - 4th edition
Probability and Statistics - 4th edition
HDU 3415 Max Sum of Max-K-sub-sequence(单调队列)
/*AC 思路:使用sum[i]存储前i个序列之和,队列中存储区间内出现过最小序列和,这样只需要sum[i]前去最小序列和即可。 */ #include using namespace std; const int nMax = 100010; const int INF = 0x7fffffff; int A[nMax]; int sum[2 * nMax];//这里需要增倍 struct Q
TMS_WebGMaps_1.9.8.0_Full_Source
TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder
【POJ1077】Eight 八数码问题,解题报告+思路+代码
#include #include #include #define INPUT using namespace std; /** Problem : poj1077,hdu1043,经典的八数码问题。 知识点: BFS + HASH + 打表 + 父亲节点记录 境界:3 - BFS+HASH+打表 A了两天!!! 记得拿启发式,双向BFS重新写
OV9734 DATASHEET,完整规格书
OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等
【HDU2222】 0.6%达成 模板题 果然无聊的时候A题才是最正确的选择啊因为你就会更加无聊
#include #include #include #include #include using namespace std; /** Reference:http://www.cnblogs.com/procedure2012/archive/2012/01/29/2331460.html Thanks to: lpp学长给的模板和讲义 Pre-Knowle
【ZOJ3587】Marlon's String——白四爷×KMP 白濑肆の算法完全解读KMP篇 KMP来袭第二弹前缀什么的果然最讨厌了!【1.0%达成!】
#include #include #include #include /** Title: 【ZOJ3587】Marlon's String——白四爷×KMP 白濑肆の算法完全解读KMP篇 KMP来袭第二弹前缀什么的果然最讨厌了!【1.0%达成!】 Problem: ZOJ3587 Marlon's String Knowledge Point : KMP算法の深
【CodeForces 155C Hometask】白濑肆×字符串+DP——果然是字符串处理什么的好讨厌啊尤其是换行符的处理看来不用CIN不行了呢DP的转移真心不会啊水到家了怎么办!【1.1%达成】
#include #include #include #include using namespace std; const int MAX_SIZE = 1e5+10; char text[MAX_SIZE]; /** Title: 白濑肆×字符串+DP——果然是字符串处理什么的好讨厌啊尤其是换行符的处理看来不用CIN不行了呢虽然效率低人家好伤心的还有就是DP的转移真心不会啊水到
【HDU4313】Matrix 多校 解题报告+AC代码+思路+算法正确性证明,此为Kruskal贪心恶心版本,非自虐倾向慎入!建议想找解题报告的童鞋看简单版本的,这个我写给自己【目标达成 0.2%】
#include #include #include #include using namespace std; /** 【警告】这个恶心版本是我写给自己看的,关于解题报告,还是请移步简单版本吧,就在这篇文章的前一篇。 c0de4fun声明:本人未给出测试数据、未声明一次AC的题均为参考解题报告自己写的。 对那些无私贡献的大神真诚
【ACM模板】HASH表(无删除功能,添查)
#include #include #include #include #include #include using namespace std; const int HASH_SIZE = 1000000; const int HASH_KEY = 17; int next[HASH_KEY][HASH_SIZE]; int hash[HASH_SIZE]; int origin_
【0.9%】SPOJ7758 Grwoing Strings 解题报告 + AC代码 + 思路 + AC自动机简短总结
#include #include #include #include #include using namespace std; const int MAX_SIZE = 1000100; /** 【0.9%】SPOJ7758 Grwoing Strings 解题报告 + AC代码 + 思路 + AC自动机简短总结 ——果然智商捉急的话就要WA到死才能AC啊人生来不是给
【ZOJ3228】白濑肆の完美算法教室补番作,0.7%达成 白濑肆×AC自动机
#include #include #include #include #include using namespace std; /** 就是一个AC自动机 但是每个单词有两个状态,[0]是可以overlap,[1]是不能overlap时候的次数 我们用last数组记录下每个不能overlap的单词出现的位置,如果 当前位置 - last[word]
【UVA11205】The broken pedometer,思路+代码,可能是最不装逼最朴素最易懂效率也最差的代码。
#include #include #include #include #include using namespace std; /** Problem : UVA11205 - The broken pedometer Begin Time: 28th/Mar/2012 11:30 a.m. Finish Time: 29th/Mar/2012 2:14 a.
【UVa10167】 Birthday Cake,思路+代码+解题报告
#include #include #include #include // #define INPUT /** Problem: UVA10167 - Birthday Cake Begin Time:22nd/Mar/2012 5:00 p.m. End Time: 22nd/Mar/2012 7:35 p.m. Last Time: 2H 35M
389



被折叠的 条评论
为什么被折叠?



