• 洛谷【P2115】[USACO14MAR]破坏Sabotage


    我对二分的理解:https://www.cnblogs.com/AKMer/p/9737477.html

    题目传送门:https://www.luogu.org/problemnew/show/P2115

    对于我们要求的一个“最小平均值”,我们可以通过二分来得到。对于我们二分的那个平均值,我们令每一个数全部减去它,然后这时删掉“最大子段和”就是最优策略。

    假设减完平均值之后的数列和为(sum),那么我们二分的平均值为(ave),要使得平均值降到(ave)以下,整个数列的权值和至少要减少(sum)。也就是说,减得越多越好,只要能减到(sum)那么多,那么最低平均值必然小于等于(ave)。因为减完之后(sum<=0),也就是平均值乘以(n)小于等于(ave*n),也就是平均值会小于等于(ave)

    总结:如果最大子段和要大于等于删完平均值之后的数列和,那么说明我可以通过删掉这一段使得平均值降低到我们二分的值或那个值以下。

    时间复杂度:(O(nloga))

    空间复杂度:(O(n))

    代码如下:

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    const double eps=1e-6;
    const int maxn=1e5+5;
    
    int n;
    int a[maxn];
    double b[maxn],sum[maxn];
    
    int read() {
    	int x=0,f=1;char ch=getchar();
    	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    	for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    	return x*f;
    }
    
    bool check(double ave) {
    	for(int i=1;i<=n;i++)
    		b[i]=a[i]-ave,sum[i]=sum[i-1]+b[i];//求前缀和
    	double mn=sum[1],fake=-1e9;//mn存1~i-1的前缀和最小值,fake存最大子段和
    	for(int i=2;i<n;i++) {
    		fake=max(fake,sum[i]-mn);//sum[i]-1~i-1的前缀和最小值就是以i结尾的最大子段和
    		mn=min(mn,sum[i]);//更新mn
    	}
    	if(fake>=sum[n])return 1;//判断平均值是否可以小于等于ave
    	return 0;	
    }
    
    int main() {
    	n=read();double l=0,r=0;
    	for(int i=1;i<=n;i++)
    		a[i]=read(),r=max(r,(double)a[i]);
    	while(l+eps<r) {
    		double mid=(l+r)/2;
    		if(check(mid))r=mid;
    		else l=mid;//实数二分
    	}
    	printf("%.3lf
    ",r);//平均值肯定不能比r小了。
    	return 0;
    }
    
  • 相关阅读:
    jQuery层级选择器
    jQuery基本选择器
    What is the difference between try/except and assert?
    glove 安装错误
    Windows10+anaconda,python3.5, 安装glove-python
    GloVe:另一种Word Embedding方法
    PyTorch在NLP任务中使用预训练词向量
    理解GloVe模型(Global vectors for word representation)
    word2vec 中的数学原理详解(二)预备知识
    Python zip() 函数
  • 原文地址:https://www.cnblogs.com/AKMer/p/9738055.html
Copyright © 2020-2023  润新知