zoukankan      html  css  js  c++  java
  • CodeForces 1358E.Are You Fired?

    题意:Levian在一家大公司当会计员。Levian知道公司连续n个月的营收,第i个月的营收是ai(正数表示盈利,负数为亏损)。由于疫情的隔离,第一个(lceil n/2 ceil)的收入是不稳定的,但是剩下的每个月的收入都是相同的。

    Levian准备告诉董事长n - k + 1个数字---每连续k个月的总营收。换句话说,对于(iin{[1, n - k + 1]}),他会说出ai + ai+1 + ... + ai+k-1个月的收入和。

    不幸的是,如果一个总收入的和<= 0,那么董事长会不高兴,并且开除Levian。为了拯救Levian的职业生涯,找到一个k值,对于每k个月来说,报告的收入都要>= 0。

    分析:
    我们先代数分析一下,我们另Sk(i) = ai + ai+1 + ... + ai+k-1,表示从i这个起点开始,连续k个月的营收总和,当k <= n / 2时,考虑下Sk(i)和Sk(i+k),我们把k乘以2,我们的S2k(i) = Sk(i) + Sk(i+k),如果我们的Sk(i) > 0,Sk(i+k)也大于0,那么S2k(i)也是大于0的,因此如果一个合法的k是存在的,那么也存在一个k' > n / 2也是合法的。仔细想下为什么这样?因为我们要求对于i属于[1, n - k + 1]的每个起点开始长度为k的区间,它们的和都要大于> 0,那么Sk(i)和Sk(i+k)也要> 0,这样我们就会得到S2k(i) > 0,意味着,我们只需要考虑k > n / 2的,如果这个k是合法的,那么会存在一个k <= n / 2的也是合法的。

    然后,当k > n / 2时,我们的[i, i + 1, i + 2, ..., i + k - 1]的最右边的数字可以肯定是x,如果x >= 0,我们考虑一下,如果存在一个k是合法的,那么k + 1也肯定是合法的,即Sk+1(i) = Sk(i) + x >= Sk(i) > 0,这样,我们只需要检查一下k == n的情况,因为既然存在一个比较小的k是合法的,当x >= 0的时候,那么后续大于k的k'也一定是合法的。

    然后,我们考虑x < 0的情况,对于一个i,我们如果找到Sp(i) > 0,如果Sp(i) > 0,那么Sp-1(i) = Sp(i) + (-x) > Sp(i) > 0也是合法的,即随着k的增加,我们的区间和的值越来越低,即对于一个p来说,那么p - 1也是合法的,我们找到对于一个i来说,它所能延长的最长的k的值,即ai + ai+1 ... ai+p,之后再加一个ai+p+1就变成< 0了,这个最长的k,这个可以采用二分查找,我们先化一下公式,我们化成PreSum[i + p - 1] - PreSum[i - 1] > 0,那么对于一个i来说,我们在前缀和区间中二分查找最后一个大于PreSum[i - 1]的前缀和。

    这样,我们找齐了所有i点所能延长的最大的k值(假设为limit[i]),对于一个可行的结果k值,我们要满足k <= min(limit[1], limit[2], limit[3], ..., limit[n - k]),为啥是到n - k呢?因为我们的i点只到[1, n - k],然后我们编写代码的时候,我们的i从1到n遍历的时候,因为对于一个可行的k值来说,如果i + k >= n的话,我们可以直接输出k就行了,在每一次遍历的时候,我们还要对这个k值取最小,即前面的limit。(见代码)

    一个小小的疑惑:我们找每个i点所能延长的最长的k值的时候,我们用反向迭代器查找最后一个大于PreSum[i - 1]的值,我们要求的i + k值应该在[i, i + n / 2]区间内的,为什么是反着的?
    有大神解释,感激不尽!

    使用反向迭代器的原因:
    关于查找最后一个大于PreSum[i - 1]的值,因为STL的二分查找只会查找上升的序列,我们可以反转序列或者使用反向迭代器然后进行查找。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    using LL = long long;
    const int N = 1000005;
    //前缀和
    LL sum[N];
    LL limit[N];
    int main()
    {
    	int n;
    	scanf("%d", &n);
    
    	for (int i = 1; i <= (n + 1) / 2; ++i)
    	{
    		scanf("%lld", &sum[i]);
    		sum[i] += sum[i - 1];
    	}
    
    	int x;
    	scanf("%d", &x);
    
    	for (int i = (n + 1) / 2 + 1; i <= n; ++i)
    	{
    		sum[i] = sum[i - 1] + x;
    	}
    
    	if (sum[n] > 0)
    	{
    		printf("%d
    ", n);
    		return 0;
    	}
    
    	if (x > 0)
    	{
    		puts("-1");
    		return 0;
    	}
    
    	vector<LL> pre;
    	for (int i = 1; i <= n; ++i)
    		pre.push_back(sum[i]);
    
    	auto revpre = pre;
    	reverse(revpre.begin(), revpre.end());
    
    	for (int i = 0; i < n; ++i)
    	{
    		limit[i] = n - (upper_bound(revpre.begin(), revpre.begin() + (n + 1) / 2 - 1, (i == 0 ? 0 : pre[i - 1])) - revpre.begin());
    	}
    
    	LL mnlimit = 1e18;
    
    	for (int i = 1; i <= n; ++i)
    	{
    		mnlimit = min(mnlimit, limit[i]);
    		if (n - i + 1 <= mnlimit)
    		{
    			printf("%lld
    ", mnlimit);
    			return 0;
    		}
    	}
    	
    	puts("-1");
    
    	return 0;
    }
    
  • 相关阅读:
    从输入url到浏览器加载过程(回答此问题的一个主干脉络)
    如何减少回流,重绘
    mac常用启动各种服务的命令
    分布式笔记搬迁
    JAVA基础
    EasyExcel引入
    mac 好用软件地址存储
    2018/4/11
    2018/04/04
    jdk各版本
  • 原文地址:https://www.cnblogs.com/pixel-Teee/p/12989720.html
Copyright © 2011-2022 走看看