(单调队列)洛谷P2629好消息,坏消息

洛谷P2629好消息,坏消息

思路:

题目可以选一个 k k k,然后按照 k ∼ n , 1 ∼ k − 1 k\sim n,1\sim k-1 kn,1k1,暴力枚举的话是 O ( n 2 ) O(n^2) O(n2)。我们可以把这个像环一样的东西拆开,即 a n + i = a i , i ∈ [ 1 , n ] a_{n+i}=a_i,i\in[1,n] an+i=ai,i[1,n],将数组变成 2 n 2n 2n的长度,然后判断长度为 n n n的每段是否符合要求。
即计算满足 ∀ ∑ i = j k a i ≥ 0 , k ∈ [ j , j + n − 1 ] \forall\sum_{i=j}^{k}a_i\ge 0,k\in[j,j+n-1] i=jkai0,k[j,j+n1]是否满足。
做一次前缀和运算,即 s u m k = ∑ i = 1 k a i sum_k=\sum_{i=1}^{k}a_i sumk=i=1kai,然后转换为满足 ∀ s u m j − s u m k ≥ 0 , k ∈ [ j , j + n − 1 ] \forall sum_j-sum_k\ge 0,k\in[j,j+n-1] sumjsumk0,k[j,j+n1]
∵ ∀ s u m j − s u m k ≥ 0 , k ∈ [ j , j + n − 1 ] \because \forall sum_j-sum_k\ge 0,k\in[j,j+n-1] sumjsumk0,k[j,j+n1]
∴ s u m j − min ⁡ { s u m k ∣ k ∈ [ j , j + n − 1 ] } ≥ 0 \therefore sum_j-\min\{sum_k|k\in[j,j+n-1]\}\ge 0 sumjmin{sumkk[j,j+n1]}0
用单调队列维护 min ⁡ { s u m k } \min\{sum_k\} min{sumk}的值,然后判断。

代码:

#include<bits/stdc++.h>
#define pii pair<int,int>
#define ll long long
#define cl(x,y) memset(x,y,sizeof(x))
#define ct cerr<<"Time elapsed:"<<1.0*clock()/CLOCKS_PER_SEC<<"s.\n";
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define lson x<<1,l,mid
#define rson x<<1|1,mid+1,r
#define INF 1e18
const int N=2e6+10;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const double eps=1e-8;
const double pi=acos(-1);
using namespace std;
int a[N],sum[N];
struct edge
{
	int v,id;
};
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int n,i,ans=0,j=0;
	cin>>n;
	sum[0]=0;
	for(i=1;i<=n;i++)
	{
		cin>>a[i];
		a[n+i]=a[i];
		sum[i]=sum[i-1]+a[i];
	}
	for(i=n+1;i<2*n;i++)
		sum[i]=sum[i-1]+a[i];
	deque<edge> q;
	for(i=1;i<2*n;i++)
	{
		while(!q.empty() && sum[i]<=q.back().v)
			q.pop_back();
		while(!q.empty() && i-n>q.front().id)
			q.pop_front();
		q.push_back({sum[i],i});
		if(i>=n)
		{
			if(q.front().v-sum[j]>=0)
				ans++;
			j++;
		}
	}
	cout<<ans<<endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值