思路:首先一个前置结论:
如果有答案,则必然有一个
的答案。
因为,如果有个答案k,那么2k也是满足的,不断倍增即可得此结论。
那么对于
的每个数,我们怎么check合法性呢?
设当前check的值为k:
显然对于任意一个
,都有
。
我们可以计算出第一段长度k的区间的
,然后区间每次右移的时候,最左端的点会被去掉,再加上新增的。由于数组后半部分的数都是一样的。所以我们可以知道,每次区间移动的时候,区间和 的变换量。
移动1次的变化为
移动2次的变化为
移动3次的变化为
那么移动p次的变化就是
即我们可以计算出任意长度的区间移动一定次数后的区间和,而我们只需要保证区间和是都要大于0即可。即移动1到n-k次中的最小值要大于0,那么显然维护一个前缀最小值就行。
ps:比赛的时候没想出正解,还憨憨冲了一发bitset。。。。。。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 5e5 + 10;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
int t,n,m,a[N],f[N];
LL sum[N],mn[N];
int main() {
scanf("%d",&n);
for(int i=1;i<=(n+1)/2;i++)scanf("%d",a+i);
scanf("%d",&m);
LL x=0,y=0;
for(int i=1;i<=(n+1)/2;i++){
x+=m-a[i];
mn[i]=min(x,mn[i-1]);
}
for(int i=1;i<=(n+1)/2;i++){
y+=a[i];
}
for(int i=(n+1)/2;i<=n;i++){
if(y+mn[n-i]>0){
return cout<<i<<'\n',0;
}
y+=m;
}
cout<<-1<<'\n';
return 0;
}