Typesetting math: 100%

【洛谷P3628】特别行动队

题目

题目链接:https://www.luogu.com.cn/problem/P3628
你有一支由 n 名预备役士兵组成的部队,士兵从 1n 编号,你要将他们拆分成若干特别行动队调入战场。出于默契的考虑,同一支特别行动队中队员的编号应该连续,即为形如 (i,i+1,i+k)的序列。所有的队员都应该属于且仅属于一支特别行动队。
编号为 i 的士兵的初始战斗力为 xi ,一支特别行动队的初始战斗力 X 为队内士兵初始战斗力之和,即 X=xi+xi+1++xi+k
通过长期的观察,你总结出对于一支初始战斗力为 X 的特别行动队,其修正战斗力 X=aX2+bX+c,其中 a, b, c 是已知的系数(a<0)。 作为部队统帅,现在你要为这支部队进行编队,使得所有特别行动队的修正战斗力之和最大。试求出这个最大和。
n106

思路

不记得从哪听说这道题不是很模板?但是感觉还是模板啊QWQ。
f[i] 表示前 i 个人分好组的最大和。设 s[i]=j=1ix[i],显然

f[i]=max(f[j]+a(s[i]s[j])2+b(s[i]s[j])+c)

展开,移项后得到

f[j]+a·s[j]2b·s[j]=2a·s[i]·s[j]+f[i]a·s[i]2b·s[i]+c

那么可以看做一条斜率为 2a·s[i],截距为 f[i]a·s[i]2b·s[i]+c 的直线,决策点为 (s[j],f[j]+a·s[j]2b·s[j]) 的平面直角坐标系。
由于 a<0,那么斜率满足单调递减,同时决策点的横坐标单调递增,所以单调队列维护上凸壳即可。
时间复杂度 O(n)

代码

#include <cctype>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;

const int N=1000010;
ll a,b,c,f[N],s[N],Y[N];
int n,l,r,q[N];

ll read()
{
	ll d=0,f=1; char ch=getchar();
	while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
	while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
	return d*f;
}

double slope(int x,int y)
{
	return 1.0*(Y[y]-Y[x])/(s[y]-s[x]);
}

int main()
{
	n=read(); a=read(); b=read(); c=read();
	for (int i=1;i<=n;i++)
		s[i]=s[i-1]+read();
	l=r=1;
	for (int i=1;i<=n;i++)
	{
		for (int x=q[l],y=q[l+1];;x=q[l],y=q[l+1])
			if (l<r && slope(x,y)>=2.0*a*s[i]) l++; 
				else break;
		int j=q[l];
		f[i]=f[j]+a*(s[i]-s[j])*(s[i]-s[j])+b*(s[i]-s[j])+c;
		Y[i]=f[i]+a*s[i]*s[i]-b*s[i];
		for (int x=q[r-1],y=q[r];;x=q[r-1],y=q[r])
			if (l<r && slope(x,y)<=slope(y,i)) r--;
				else break;
		q[++r]=i;
	}
	printf("%lld",f[n]);
	return 0;
}
posted @   stoorz  阅读(135)  评论(0编辑  收藏  举报
编辑推荐:
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
阅读排行:
· 为DeepSeek添加本地知识库
· .NET程序员AI开发基座:Microsoft.Extensions.AI
· 精选4款基于.NET开源、功能强大的通讯调试工具
· 数据不出内网:基于Ollama+OneAPI构建企业专属DeepSeek智能中台
· 大模型工具KTransformer的安装
点击右上角即可分享
微信分享提示