洛谷P1714切蛋糕题解

题目描述

今天是小 Z 的生日,同学们为他带来了一块蛋糕。这块蛋糕是一个长方体,被用不同色彩分成了 \(n\) 个相同的小块,每小块都有对应的幸运值。

小 Z 作为寿星,自然希望吃到的蛋糕的幸运值总和最大,但小 Z 最多又只能吃 \(m(m\le n)\) 小块的蛋糕。

请你帮他从这 \(n\) 小块中找出连续的 \(k(1 \le k\le m)\) 块蛋糕,使得其上的总幸运值最大。

形式化地,在数列 \(\{p_n\}\) 中,找出一个子段 \([l,r](r-l+1\le m)\),最大化 \(\sum\limits_{i=l}^rp_i\)

题目分析

欸?这题这么简单?这不就暴力枚举左右端点,前缀和数组 \(O(1)\) 查询区间和,取最大值不就行了?

嗯……是个好思路,够暴力,但是吧……

对于 \(20\%\) 的数据,有 \(1\le n\le100\)
对于 \(100\%\) 的数据,有 \(1\le n\le5\times 10^5\)

暴力做法好像不太行

考虑优化

\(1\)\(n\) 枚举右端点r,设此时左端点为l,最后幸运值总和就是sum[r]-sum[l-1]

由于我们要最大化幸运值,因此我们希望sum[l-1]最小

题目中还有一个限制

小 Z 最多只能吃 \(m(m\le n)\) 小块的蛋糕。

因此 \(r-l+1 \le m\)

所以我们要找到的就是在以r-1为右端点的,长度为m-1的区间中的最小值

这道题至此就被成功的转化为了滑动窗口求最值的问题

可以用单调队列来维护

AC代码

#include<iostream>
#include<deque>

using namespace std;

const int N=500010;

int n,m;
int a[N];
int ans=-2e9;
deque<int> q;

int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		a[i]+=a[i-1];
	}
	for(int i=0;i<=n;i++)
	{
		while(!q.empty()&&q.front()<i-m+1)
			q.pop_front();
		while(!q.empty()&&a[q.back()]>a[i])
			q.pop_back();
		q.push_back(i);
		ans=max(ans,a[i]-a[q.front()]);
	}
	cout<<ans<<endl;
	
	return 0;
} 

完结撒花~~~

posted @ 2022-08-15 19:49  OrangeStar*  阅读(152)  评论(0编辑  收藏  举报