【Codeforces Round #645 (Div. 2) E】 Are You Fired?

题目链接

【题目翻译】

给你一个长度为n的序列a,但是只给你前[n/2](向上取整)个数字,然后后面[n/2](向下取整)个数字都是

x,现在让你求一个数字k,使得序列a中每个长度为k的连续序列的和都大于0.

【题解】

我们先证,如果存在一个满足要求的k的话,那么k2=2*k肯定也是一个符合要求的答案。

为什么?

我们可以假设s[i]=a[i]+a[i+1]+a[i+2]+...+a[i+k-1]

则因为k满足要求,所以对于任意一个s[i],都有s[i]>0

那么对于k2=2*k,同样定义个大号版的S[i] = s[i] + s[i+k]

因为每个s[i]都大于0,则S[i]肯定也是大于0的。

所以如果最后有答案的话,肯定有一个大于等于n/2(向上取整)的满足要求的k.

这就很有用了。

仍然是上面定义的si

我们看一下s[i+1]和s[i]的关系。会发现s[i+1]=s[i]+a[i+k]-a[i]

这是不是有点类似前缀和的样子,实际上会发现s[i]就是由这么一个数组的前缀和

即p={s1,a[1+k]-a[1],a[2+k]-a[2],......,a[n]-a[n-k]}

这玩意有啥用呢?其实就是说 如果我们能够让某个k,使得对应的这个数组p的每个前缀和都大于0,那么我们就找到了答案。

这个p现在有点复杂,但是想想题目给我们的条件?后半部分都是x,所以a[1+k],a[2+k]...都是x呀!

那p={s1,x-a[1],x-a[2],....,x-a[n-k]}

但是我们要怎么找到这么合适的一个k呢,肯定是枚举了(大于等于n/2嘛),所以我们考虑一下如果k+1了,这个p数组会变成啥样。

即p={s1+x,a[2+k]-a[1],a[3+k]-a[2],....a[n]-a[n-k-1]},然后把x代入。

p={s1+x,x-a[1],x-a[2],...,x-a[n-k-1]}。所以这个p数组,实际上就只是减少了一个元素,然后第一位加上了x。

时刻注意 我们只关注这个数组的前缀和的里面的最小值。

而s[i]=p[1]+p[2]+p[3]+...+p[i],即
s[]={p1,p1+p2,p1+p2+p3,....,p1+p2+p3+...+p[n-k+1]}

既然第一个元素很麻烦,那我们就把每个s[i]都去掉p[1],则我们得到一个新的s数组(算答案的时候加上p1就行,不影响正常的求最小值)

s[]={0,p2,p2+p3,...,p2+p3+...+p[n-k]};

会发现,对于不同的k,这个数组都是一样的!(就是k越大,长度会减小1).

那么我们就可以求出来一个m[]数组,这个m数组中m[i] = min{s[1],s[2]...s[i]} (这个很好求的,用个变量累加x-a[i],然后求最小就好)。

这样,对于我们枚举的K,直接看p1+mn-K+1是不是大于0就好了。

如果不是的话,p1递增x(因为k变大1了)继续判断。

【代码】

#include<bits/stdc++.h>
#define ll long long
#define rei(x) scanf("%d",&x)
#define rel(x) scanf("%I64d",&x)
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
using namespace std;

const int N = 50e4;

int T,n,nn,x;
int a[N+10];
ll m[N+10];

int main(){
    //cout<<(1LL<<62)<<endl;
    #ifdef LOCAL_DEFINE
        freopen("D:\\rush.txt","r",stdin);
    #endif
    ios::sync_with_stdio(0),cin.tie(0);
    cin >> n;
    nn = (n+1)/2;
    rep1(i,1,nn) cin >> a[i];
    cin >> x;
    m[1] = 0;
    ll sum = 0;
    rep1(i,2,n-nn+1){
        sum += x-a[i-1];
        m[i] = min(m[i-1],sum);
    }
    sum = 0;
    rep1(i,1,nn) sum+=a[i];
    int ans = -1;
    rep1(k,nn,n){
        if (sum+m[n-k+1]>0){
            ans = k;
            break;
        }
        sum+=x;
    }
    cout<<ans<<endl;
    return 0;
}

posted @ 2020-05-30 16:35  AWCXV  阅读(135)  评论(0编辑  收藏  举报