zoukankan      html  css  js  c++  java
  • 牛客练习赛 小A与最大子段和 解题报告

    小A与最大子段和

    题意

    在一个序列 ({a}) 里找到一个非空子段 ({b}), 满足 (sumlimits_{i=1}^{|b|}b_i imes i) 最大

    (nle 200000,|a_i|le 2000)


    长的都一脸的斜率优化

    考虑表示一个子段([l+1,r])

    [egin{aligned} &sum_{i=l+1}^ra_i(i-l)\ &=sum_{i=l+1}^ra_i imes i-a_i imes l end{aligned} ]

    (A_k=sum_{i=1}^k a_ii,B_k=sum_{i=1}^k a_i)

    那继续化简为

    [A_r-B_r imes l+B_l imes l-A_l ]

    然后我们枚举(r),想办法搞一下(l)

    维护一个((i,B_i imes i-A_i))的上凸包,然后发现是对斜率询问最大截距,直接在凸包上三分就可以了。


    Code:

    #include <cstdio>
    #include <algorithm>
    #define ll long long
    const int N=2e5+10;
    using std::max;
    int n,tot;
    ll A[N],B[N];
    struct Point
    {
    	ll x,y;
    	Point(){}
    	Point(ll X,ll Y){x=X,y=Y;}
    	Point friend operator -(Point a,Point b){return Point(a.x-b.x,a.y-b.y);}
    	ll cal(ll d){return d*x+y;}
    }s[N];
    ll Cross(Point a,Point b){return a.x*b.y-a.y*b.x;}
    void ins(Point a)
    {
    	while(tot>1&&Cross(a-s[tot],s[tot]-s[tot-1])<=0) --tot;
    	s[++tot]=a;
    }
    int main()
    {
    	scanf("%d",&n);
    	ins(Point(0,0));
    	ll ans=-(1ll<<50),a;
    	for(int i=1;i<=n;i++)
     	{
     		scanf("%lld",&a);
     		A[i]=A[i-1]+a*i;
     		B[i]=B[i-1]+a;
     		int l=1,r=tot;
     		while(l<r)
     		{
     			int mid=l+r>>1;
     			if(s[mid].cal(-B[i])<s[mid+1].cal(-B[i])) l=mid+1;
     			else r=mid;
     		}
     		ans=max(ans,A[i]+s[l].cal(-B[i]));
     	    ins(Point(i,B[i]*i-A[i]));
     	}
     	printf("%lld
    ",ans);
    	return 0;
    }
    

    2019.2.16

  • 相关阅读:
    10 期末大作业
    09 spark连接mysql数据库
    08 学生课程分数的Spark SQL分析
    07 从RDD创建DataFrame
    06 Spark SQL 及其DataFrame的基本操作
    05 RDD编程
    05 RDD练习:词频统计
    04 RDD编程练习
    Spark RDD编程
    Spark架构与运行流程
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10388170.html
Copyright © 2011-2022 走看看