洛谷P2629好消息,坏消息
思路:
题目可以选一个
k
k
k,然后按照
k
∼
n
,
1
∼
k
−
1
k\sim n,1\sim k-1
k∼n,1∼k−1,暴力枚举的话是
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=jkai≥0,k∈[j,j+n−1]是否满足。
做一次前缀和运算,即
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]
∀sumj−sumk≥0,k∈[j,j+n−1]。
∵
∀
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]
∵∀sumj−sumk≥0,k∈[j,j+n−1]
∴
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
∴sumj−min{sumk∣k∈[j,j+n−1]}≥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;
}