bzoj 3156: 防御准备

本文深入探讨了一种解决战线最小化问题的策略,通过斜率优化算法实现了高效的战线成本计算。重点介绍了如何通过将原始问题进行倒置处理,并利用斜率转移来优化计算过程,最终得到最小战线花费。该算法适用于大规模数据集,展现了其在战线优化问题上的高效性和实用性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

Input

第一行为一个整数N表示战线的总长度。

第二行N个整数,第i个整数表示在位置i放置守卫塔的花费Ai。

Output

共一个整数,表示最小的战线花费值。

Sample Input



10
2 3 1 5 4 5 6 3 1 2

Sample Output


18

HINT



1<=N<=10^6,1<=Ai<=10^9

Source

Katharon+#1


好久没写代码了。刚好有人问这题我就稍微写下练练手。

结果写错了。翻以前的发现以前是抄标程的。。那就写篇题解好了

斜率优化

把a[i]倒置,f[i]表示最后一个防御塔在a[i]的花费

初始方程:f[i]=min(f[j]+(i-j)*(i-j-1)/2)+a[i]

设j>k且j优于k

j,k分别带入初始方程

移项得(2*(f[j]-f[k])+j*(j+1)-k*(k+1))/2(j-k)<i

维护斜率转移即可

ans=min(ans,f[i]+(n-i+1)*(n-i)/2)


#include<cstdio>
#include<algorithm>
using namespace std;
long long f[1000001];
long long a[1000001];
int q[1000001];
inline double getk(int k,int j)
{
	return double((double)2*(double)(f[j]-f[k])+(double)j*(double)(j+1)-(double)k*(double)(k+1))/double((double)2*(double)(j-k));
}
int main()
{
	int n;
	scanf("%d",&n);
	int i;
	for(i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	for(i=1;i<=n/2;i++)
	{
		long long t=a[i];
		a[i]=a[n+1-i];
		a[n+1-i]=t;
	}
	long long ans=a[1]+(long long)n*(long long)(n-1)/(long long)2;
	int l=1,r=1;
	q[1]=1;
	f[1]=a[1];
	for(i=2;i<=n;i++)
	{
		while(getk(q[l],q[l+1])<(double)i&&l<r)
			l++;
		f[i]=f[q[l]]+(long long)(i-q[l])*(long long)(i-q[l]-1)/(long long)2+a[i];
		ans=min(ans,f[i]+(long long)(n-i+1)*(long long)(n-i)/(long long)2);
		while(getk(q[r-1],q[r])>getk(q[r],i)&&l<r)
			r--;
		r++;
		q[r]=i;
	}
	printf("%lld\n",ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值