zoukankan      html  css  js  c++  java
  • 【牛客练习赛40】D 小A与最大子段和

    题目

    题目链接:https://ac.nowcoder.com/acm/contest/369/D
    在一个序列 \(a\) 里找到一个非空子段 \(b\),使 \(\sum^{m}_{i=1} b[i]\times i\) 最大。

    思路

    考虑枚举右端点 \(r\)。那么我们需要找到一个左端点 \(l\),使得 \(\sum^{r}_{i=l}a[i]\times (i-l+1)\) 最大。
    \(sum[i]=\sum^{i}_{j=1}a[j],spow[i]=\sum^{i}_{j=1}a[j]\times j\),那么

    \[\sum^{r}_{i=l}a[i]\times (i-l+1)=spow[r]-spow[l-1]-(l-1)\times (sum[r]-sum[l-1]) \]

    所以有

    \[ans=max(ans,spow[r]-spow[l-1]-(l-1)\times (sum[r]-sum[l-1])) \]

    也就是

    \[sum[j]\times j-spow[j]=sum[i]\times j-s[i]+ans \]

    我们要让截距最大,那么就将 \((j,sum[j]\times j-spow[j])\) 扔进栈里,维护上凸壳即可。
    时间复杂度 \(O(n\log n)\)

    代码

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    
    const int N=200010;
    int n,top,st[N];
    ll ans,sum[N],spow[N],X[N],Y[N];
    
    double slope(int x,int y)
    {
    	if (X[x]==X[y]) return 1000000000000.0;
    	return 1.0*(Y[x]-Y[y])/(X[x]-X[y]);
    }
    
    int binary(int x)
    {
    	int l=1,r=top-1,mid;
    	while (l<=r)
    	{
    		mid=(l+r)>>1;
    		if (slope(st[mid],st[mid+1])<=1.0*sum[x]) r=mid-1;
    			else l=mid+1;
    	}
    	return st[r+1];
    }
    
    int main()
    {
    	ans=-2333333333333333333LL;
    	scanf("%d",&n);
    	top=1;
    	for (int i=1,x;i<=n;i++)
    	{
    		scanf("%d",&x);
    		sum[i]=sum[i-1]+x;
    		spow[i]=spow[i-1]+x*i;
    		Y[i]=sum[i]*i-spow[i]; X[i]=i;
    		
    		int j=binary(i);
    		ans=max(ans,spow[i]-spow[j]-(sum[i]-sum[j])*j);
    		while (top && slope(st[top-1],st[top])<slope(st[top],i))
    			top--;
    		st[++top]=i;
    	}
    	printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    vue-cli+typescript 搭建
    es6基础知识
    上机作业六 磁盘管理综合测试2019 7 31
    上机作业五 磁盘配额 2019 7 2
    上机作业四 磁盘管理 2019 7 31
    上机作业三 账号管理2019 7 31
    上机作业 2 2019/7/26
    Linux系统管理06--磁盘管理
    Linux系统管理05--权限及归属管理
    chapter06-07磁盘管理
  • 原文地址:https://www.cnblogs.com/stoorz/p/13144743.html
Copyright © 2011-2022 走看看