小A与最大子段和 斜率优化 + 二分 + 细节

Code: 

#include <bits/stdc++.h>
#define setIO(s) freopen(s".in","r",stdin) 
#define x(i) (1.0000*i) 
#define y(i) (1.0000*s2[i]*i-1.00000*s1[i])        
#define maxn 300000
#define ll long long  
#define ldb double
using namespace std;
int tail,head,n; 
int q[maxn]; 
ll s1[maxn],s2[maxn],f[maxn];     
ldb slope(int i,int j) { return (ldb)(1.0*y(i)-y(j))/(ldb)(1.0*x(i)-x(j));    }   
int main()
{ 
	int i,j;  
	ll ans=-1e18; 
	// setIO("input");  
	scanf("%d",&n);
	for(i=1;i<=n;++i) 
	{
		scanf("%lld",&s2[i]); 
		s1[i]=s1[i-1]+s2[i]*i; 
		s2[i]+=s2[i-1];        
	}
	head=tail=1; 
	for(i=1;i<=n;++i) 
	{
		int l=head,r=tail,re=0,mid=0; 
		while(l<=r) 
		{
			mid=(l+r)>>1;  
			if(mid==tail) { re=tail;  break;    }
			if(slope(q[mid],q[mid+1])<=s2[i]) re=mid,r=mid-1; 
			else l=mid+1;  
		}
		f[i]=s1[i]-s1[q[re]]-(s2[i]-s2[q[re]])*q[re]; 
		ans=max(ans,f[i]);   
		while(head<tail&&slope(i,q[head-1])>slope(q[head],q[head-1])) --tail;    
		q[++tail]=i; 
	}  
	printf("%lld\n",ans);   
	return 0; 
} 

  

猜你喜欢

转载自www.cnblogs.com/guangheli/p/11143029.html