[洛谷]P3594 [POI2015]WIL-Wilcze doły (#單調隊列)

題目描述

給定一個長度爲n的序列,你有一次機會選中一段連續的長度不超過d的區間,將裏面所有數字全部修改爲0。請找到最長的一段連續區間,使得該區間內所有數字之和不超過p。

輸入格式

第一行包含三個整數n,p,d(1<=d<=n<=2000000,0<=p<=10^16)。第二行包含n個正整數,依次表示序列中每個數wi

輸出格式

包含一行一個正整數,即修改後能找到的最長的符合條件的區間的長度。

輸入輸出樣例

輸入 #1複製

9 7 2
3 4 1 9 4 1 7 1 3

輸出 #1複製

5

說明/提示

給定一個長度爲n的序列,你有一次機會選中一段連續的長度不超過d的區間,將裏面所有數字全部修改爲0。

請找到最長的一段連續區間,使得該區間內所有數字之和不超過p。


思路

選擇每一個位置i作爲結尾能形成的最長區間的左端點是單調不降的。

#include <stdio.h>
#include <iostream>
#include <deque>
#define N 2000001
#define ll long long int 
using namespace std;
ll n,p,d,s,t[N],last(1);
struct node
{
	ll val;
	ll position;
	ll sum;
}a[N];
deque<node> dq;
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	register ll i,j;
	cin>>n>>p>>d;
	for(i=1;i<=n;i++)
	{
		cin>>a[i].val;//a[i]
		a[i].position=i;//序列位置 
		a[i].sum=a[i-1].sum+a[i].val;//前綴和 
	}
	for(i=d;i<=n;i++)
	{
		t[i]=a[i].sum-a[i-d].sum;//算區間[i-d+1,i]的和 
	}
	s=d;//答案至少爲d 
	a[0].position=d;
	dq.push_back(a[0]);
	for(i=d+1;i<=n;i++)
	{
		while(!dq.empty() && t[dq.back().position]<t[i])
			dq.pop_back();
		dq.push_back(a[i]);
		while(!dq.empty() && dq.front().position-d+1<last)//如果隊首元素的左端點比last小,那就彈出 
			dq.pop_front();
		while(!dq.empty() && a[i].sum-a[last-1].sum-t[dq.front().position]>p)
		{
			last++;
			while(!dq.empty() && dq.front().position-d+1<last)
				dq.pop_front();
		}
		s=max(s,i-last+1);
	}
	cout<<s<<endl;
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章