zoukankan      html  css  js  c++  java
  • cf 1358E. Are You Fired?(双指针+贪心)

    题目:传送门

    思路:若存在答案 k , 那么一定有答案 m * k (其中m=1、2、3、...... 且 m * k <= n ),可推出 一定存在答案 k' > n/2 (后者是前者的必要条件);  【显然 两个相邻长度为 k 的区间的和都>=0 , 合并后也>=0;】

       这道题的精髓也就在 不等式 k' > n/2 上。如果你对接下来的叙述有任何疑惑,请记住 k' > n/2 。

       当 x >= 0 , 对于任意左端点 L <= (n+1)/2 , 对应的长度为 k' 的区间 [ L , L + k' - 1 ] , 而 L + k' - 1 > (n+1)/2 (由 k' > n/2 得),故 L 对应的区间与最后的 [n/2] 相交,而 x >= 0 ,  因此将右端点右移可使区间和变大,对于每个 L 对应的区间,右端点取到n可使区间和最大,那么只需要判断 [1,n] 的区间和即可 。 (最后[n/2] 个数字都是>=0 的,因此如果存在答案k  --> k' > n/2, 那么 k'' = n 也应该同样满足; 后者是前者的必要条件)

       当 x < 0 , 对于任意左端点 L <= (n+1)/2 , 对应的长度为 k' 的区间 [ L , L + k' - 1 ]  , 若 区间和 sum <=0 , 那么就将其的右端点左移 (区间右边部分都是 x < 0),使其满足 sum > 0 。(双指针思想+贪心)那么可以设置 初始L = 1 和 初始答案 k = n , k越大,那么长度为k的区间数就越少(区间和的约束也就越少) ,且对于 区间[ L , L + k -1 ] ,其区间和若 > 0 ,那么 [ L , R ] 的区间和也 > 0 , (n+1)/2 < R < L + k -1 ,若区间和 < 0 , 则 k-- 。 对于 L = i 的对应的区间 ,当k--时 , 则 L' < i 的区间长度也变短 ,其区间和减去一个负数,且之前已经处理过的L ' 对应的区间和是 > 0 的,那么减去负数也还是 > 0 。

       一开始,发现 k 类似于一个多峰值函数,但采用一定贪心策略能够使其具有单调性,之后就可以用双指针求解了。至于快速获取区间和,可以先预处理前缀和。

    #include<bits/stdc++.h>
    /*
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<vector>
    #include<cctype>
    #include<queue>
    #include<algorithm>
    #include<map>
    #include<set>
    */
    #pragma GCC optimize(2)
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    typedef pair<double,double> pdd;
    const int N=1e6+5;
    const int M=1e4+5;
    const int inf=0x3f3f3f3f;
    const LL mod=1e9+7;
    const double eps=1e-9;
    const long double pi=acos(-1.0L);
    #define ls (i<<1)
    #define rs (i<<1|1)
    #define fi first
    #define se second
    #define pb push_back
    #define mk make_pair
    #define mem(a,b) memset(a,b,sizeof(a))
    LL read()
    {
        LL x=0,t=1;
        char ch;
        while(!isdigit(ch=getchar())) if(ch=='-') t=-1;
        while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); }
        return x*t;
    }
    int a[N];
    LL sum[N];
    int main()
    {
        int n=read();
        for(int i=1;i<=(n+1)/2;i++) a[i]=read();
        int x=read();
        for(int i=(n+1)/2+1;i<=n;i++) a[i]=x;
        for(int i=1;i<=n;i++) sum[i]=a[i]+sum[i-1];
        if(x>=0)
        {
            if(sum[n]>0) printf("%d
    ",n);
            else printf("-1
    ");
            return 0;
        }
        int len=n;
        for(int i=1;i<=n;i++)
        {
            int j=i+len-1;
            if(j>n||len<=n/2) break;
            LL t=sum[j]-sum[i-1];
            while(t<=0&&len>n/2) t-=x,len--;
        }
        if(len<=n/2) printf("-1
    ");
        else printf("%d
    ",len);
        return 0;
    }
    View Code
  • 相关阅读:
    【中位数 均分纸牌】 糖果传递
    【模板】 均分纸牌
    【离散化】 电影
    【离散化】 区间和
    【最大子矩阵】 城市游戏
    vue中如何引入Element-ui
    详细教你:如何搭建vue环境和创建一个新的vue项目
    vue中如何引入bootstrap
    十天冲刺(4)
    十天冲刺(3)
  • 原文地址:https://www.cnblogs.com/DeepJay/p/12976595.html
Copyright © 2011-2022 走看看