• 【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;
    }
    
    
  • 相关阅读:
    XML 增、删、改和查示例
    DataGrid 完全攻略之三(实现删除全选或者全不选)
    DataGrid 完全攻略之七(实现选择、编辑和修改)
    ASP.NET 2.0,无刷新页面新境界
    DataGrid 完全攻略之二(把数据导出到Excel)
    ASP.NET 2.0角色及成员管理
    动态改变页面的CSS样式
    ASP.NET 2.0新控件、管理外观、布局及其它用户体验
    页面一postback,它就显示页面的最顶端,怎样让它定位在某一位置?
    20100120 ~ 20100220 小结与本月计划
  • 原文地址:https://www.cnblogs.com/AWCXV/p/12993458.html
Copyright © 2020-2023  润新知