【XSY2787】Mythological VII 贪心

题目描述

  有两个指针\(l,r\),初始时\(l=r=k\)

  给你\(a_1,\ldots,a_n\),你要移动\(l,r\)\(l\)只能每次向左移一个数,\(r\)只能向右移一个数,要求任意时刻\((l,r]\)这个区间内的数的和\(\leq 0\)

  求\(l,r\)能否都移动到端点。

  \(n\leq 100000\)

题解

  求前缀和\(s\),约束转化为任意时刻\(s_l\geq s_r\)

  每一个时刻的决策是:

  如果\(l\)能在合法的情况下移动到\(l'\),满足\(s_{l'}>s_l\),且是所有合法的位置中最大的,就把\(l\)移到\(l'\)\(r\)同理。

  如果左边的最小值\(<\)右边的当前位置,就无解。

  否则只能贪心移动了。这种情况左边右边剩下的\(s\)都在\([s_l,s_r]\)内。

  如果左边的最大值小于右边的最大值,就把\(r\)向右移一位,否则就把\(l\)向左移一位。

  时间复杂度:\(O(n)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
ll s[100010];
ll a[100010];
int fl[100010];
int fr[100010];
ll premax[100010];
ll sufmax[100010];
ll premin[100010];
ll sufmin[100010];
const ll inf=0x3fffffffffffffffll;
int sl1[100010];
ll sl2[100010];
int sr1[100010];
ll sr2[100010];
int st[100010];
int top;
int solve()
{
	int n,k;
	scanf("%d%d",&n,&k);
	s[0]=0;
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		s[i]=s[i-1]+a[i];
	}
	premax[0]=-inf;
	premin[0]=inf;
	for(int i=1;i<=n;i++)
	{
		premax[i]=max(s[i],premax[i-1]);
		premin[i]=min(s[i],premin[i-1]);
	}
	sufmax[n+1]=-inf;
	sufmin[n+1]=inf;
	for(int i=n;i>=1;i--)
	{
		sufmax[i]=max(s[i],sufmax[i+1]);
		sufmin[i]=min(s[i],sufmin[i+1]);
	}
	top=0;
	for(int i=1;i<=n;i++)
	{
		sl2[i]=s[i];
		while(top&&s[st[top]]<s[i])
		{
			sl2[i]=min(sl2[i],sl2[st[top]]);
			top--;
		}
		if(top)
			sl1[i]=st[top];
		else
			sl1[i]=i;
		st[++top]=i;
	}
	top=0;
	for(int i=n;i>=1;i--)
	{
		sr2[i]=s[i];
		while(top&&s[st[top]]>s[i])
		{
			sr2[i]=max(sr2[i],sr2[st[top]]);
			top--;
		}
		if(top)
			sr1[i]=st[top];
		else
			sr1[i]=i;
		st[++top]=i;
	}
	int l=k,r=k;
	while(1)
	{
		if(l!=1&&sl1[l]!=l&&sl2[l]>=s[r])
		{
			l=sl1[l];
			continue;
		}
		if(r!=n&&sr1[r]!=r&&sr2[r]<=s[l])
		{
			r=sr1[r];
			continue;
		}
		if(l==1)
		{
			if(sufmax[r]>s[l])
				return 0;
			return 1;
		}
		if(r==n)
		{
			if(premin[l]<s[r])
				return 0;
			return 1;
		}
		if(premax[l-1]<sufmax[r+1])
			if(s[r+1]<=s[l])
				r++;
			else
				return 0;
		else
			if(s[l-1]>=s[r])
				l--;
			else
				return 0;
	}
	return 1;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
#endif
	int t;
	scanf("%d",&t);
	while(t--)
		if(solve())
			printf("Yes\n");
		else
			printf("No\n");
	return 0;
}
posted @ 2018-03-20 20:00  ywwyww  阅读(303)  评论(0编辑  收藏  举报