【NKOJ3545】单调队列

单调队列是也。 NKOJ3545 我们发现,本题的时间复杂度必须是线性的,时间复杂度只能是 O(NT) 于是我们考虑如果如果原函数是单调的,前缀和也是单调的,那么本题就很好搞了。 在这种特殊情况下,我们利用单调队列,一个指向开头一个指向末尾。 由于sum[r]-sum[l]>=p时,向右移动r不会对答案进行更新 由于sum[r]-sum[l]<p时,向右移动l不会对答案更新,那么这个就很好,显然满足单调队列,那么我们就一直将R右移将L右移,始终满足sum[r]-sum[l]>=p (当sum[r]-sum[l+1]<p特判一下) 可是原数列中有负数怎么搞?不满足单调性啊啊啊? 我们开个结构体,将前缀和排个序就可以满足单调性了呀! code:
#include<stdio.h>
#include<bits/stdc++.h>
#define int long long 
using namespace std;
struct node
{
	int sum,x;
}z[100005];
int t;
int n;
int X;
bool cmp(node aa,node bb)
{
	return aa.sum<bb.sum;
}
int ansl,ansr,ans,L;
int anz;
void change(int l,int r)
{
	int zhi = z[r].sum - z[l].sum ;
	int L = min(z[l].x,z[r].x);
	int R=max(z[l].x,z[r].x);
	L++; 
	if(abs(X-zhi)>ans) return ;
	if(abs(X-zhi)==ans) 
	{
		if(L<ansl) 
		{
			ansl = L; ansr = R; anz =zhi;
		}
		else if(L==ansl&&R<ansr)
		{
			ansr = R; anz = zhi;
		}
		return;
	}
	ans = abs(X-zhi);
	ansl = L;
	ansr = R;
	anz = zhi;
}
void solve()
{
	ans = 0x3f3f3f3f;
	L =  1;
	for(int i=2;i<=n;i++)
	{
		while( L<i-1&&z[i].sum-z[L+1].sum-X>=0 ) change(L,i),++L;		
		if(L<i-1) change(L+1,i); change(L,i);
	}
	change(L,n); 
	printf("%lld %lld %lld\n",anz,ansl,ansr);
}
main()
{
	scanf("%lld%lld",&n,&t);
	for(int i=1;i<=n;i++) 
	{
		scanf("%lld",&z[i].sum); z[i].sum = z[i-1].sum+z[i].sum;
		z[i].x = i;
	}
	z[++n].x = 0; z[n].sum = 0;
	sort(z+1,z+1+n,cmp);
	for(int i=1;i<=t;i++) scanf("%lld",&X),solve();
}
 
posted @ 2018-07-09 20:11  Newuser233  阅读(5)  评论(0)    收藏  举报