[尺取法+单调队列]Wilcze doły
题目描述
给定一个长度为n的序列,你有一次机会选中一段连续的长度不超过d的区间,将里面所有数字全部修改为0。
请找到最长的一段连续区间,使得该区间内所有数字之和不超过p。
请找到最长的一段连续区间,使得该区间内所有数字之和不超过p。
输入
第一行包含三个整数n,p,d(1<=d<=n<=2000000,0<=p<=10^16)。
第二行包含n个正整数,依次表示序列中每个数w[i](1<=w[i]<=10^9)。
第二行包含n个正整数,依次表示序列中每个数w[i](1<=w[i]<=10^9)。
输出
包含一行一个正整数,即修改后能找到的最长的符合条件的区间的长度。
样例输入
9 7 2
3 4 1 9 4 1 7 1 3
样例输出
5
提示
将第4个和第5个数修改为0,然后可以选出区间[2,6],总和为4+1+0+0+1=6。
思路:用尺取法移动查询区间;查询一段区间内的最大修改值,ST表会MLE,需要用单调递减队列维护该值;
AC代码:
#include <iostream> #include<cstdio> #include<algorithm> typedef long long ll; using namespace std; ll n,p,d; ll s[2000005],x[2000005]; ll q[2000005]; int main() { scanf("%lld%lld%lld",&n,&p,&d); ll tmp; for(ll i=1;i<=n;i++) {scanf("%lld",&tmp);s[i]=s[i-1]+tmp;} for(ll i=1;i<=n;i++) x[i]=s[i]-s[i-min(i,d)]; ll ans=0; ll h=1,t=0; for(ll l=1,r=1;r<=n;r++){ while(t>=h&&x[q[t]]<=x[r]) t--; q[++t]=r; while(s[r]-s[l-1]-x[q[h]]>p) { l++; while(h<t&&q[h]-min(q[h],d)+1<l) h++; } ans=max(ans,r-l+1); } printf("%lld\n",ans); return 0; }
转载请注明出处:https://www.cnblogs.com/lllxq/