1. 程式人生 > >[bzoj2086][Poi2010]Blocks_單調棧_雙指針

[bzoj2086][Poi2010]Blocks_單調棧_雙指針

ont ++ 一段 space include ... blocks mes while

Blocks bzoj-2086 Poi-2010

題目大意題目鏈接

註釋:略。


想法:首先,不難發現,如果連續的一段數的平均值不小於輸入的k的話,這段數是滿足題意的。

所以,我們再次簡化一下:將每個數都減去k,即求極大區間,使得區間和為正。

將所有數的前綴和自尾至頭壓進單調棧,然後左指針遍歷1->n,右指針在單調棧上掃即可。

最後,附上醜陋的代碼... ...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1000010 
using namespace std;
typedef long long ll;
ll q[N],top,n,m;
ll a[N],sum[N];
inline char nc()
{
	static char *p1,*p2,buf[100000];
	return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
ll read()
{
	ll x=0; char c=nc();
	while(!isdigit(c)) c=nc();
	while(isdigit(c)) x=(x<<3)+(x<<1)+c-‘0‘,c=nc();
	return x;
}
void dispose(ll val)
{
	ll ans=0;
	for(int i=1;i<=n;i++)
	{
		sum[i]=sum[i-1]+a[i]-val;
	}
	top=0;
	for(int i=1;i<=n;i++)
	{
		if(sum[q[top]]>sum[i]) q[++top]=i;
	}
	for(int i=n,j=top;i>=0;i--)
	{
		while(j&&sum[q[j-1]]<=sum[i]) j--;
		ans=max(ans,i-q[j]);
	}
	printf("%lld ",ans);
}
int main()
{
	n=read(),m=read();
	for(int i=1;i<=n;i++)
	{
		a[i]=read();
	}
	ll x;
	for(int i=1;i<=m;i++)
	{
		x=read();
		dispose(x);
	}
	puts("");
	return 0;
}

小結:%%%xqz

[bzoj2086][Poi2010]Blocks_單調棧_雙指針