版权声明:欢迎dalao指出错误暴踩本SD,蒟蒻写的博客转载也要吱一声 https://blog.csdn.net/enjoy_pascal/article/details/89044917
description
你有一支由n名预备役士兵组成的部队,士兵从1到n编号,要将他们拆分成若干特别行动队调入战场。出于默契的考虑,同一支特别行动队中队员的编号应该连续,即为形如(i, i + 1, …, i + k)的序列。 编号为i的士兵的初始战斗力为xi ,一支特别行动队的初始战斗力x为队内士兵初始战斗力之和,即x = xi + xi+1 + … + xi+k。 通过长期的观察,你总结出一支特别行动队的初始战斗力x将按如下经验公式修正为x’:x’ = ax2 + bx + c,其中a, b, c是已知的系数(a < 0)。 作为部队统帅,现在你要为这支部队进行编队,使得所有特别行动队修正后战斗力之和最大。试求出这个最大和。 例如,你有4名士兵,x1 = 2, x2 = 2, x3 = 3, x4 = 4。经验公式中的参数为a = –1, b = 10, c = –20。此时,最佳方案是将士兵组成3个特别行动队:第一队包含士兵1和士兵2,第二队包含士兵3,第三队包含士兵4。特别行动队的初始战斗力分别为4, 3, 4,修正后的战斗力分别为4, 1, 4。修正后的战斗力和为9,没有其它方案能使修正后的战斗力和更大。
analysis
-
达成成就一天两斜率优化 -
设 表示到第 位的最小值,那么 的 方程很好写
- 对于 且 比 优则有
- 拆项移项得
- 再移
- 最后
-
然后按套路上单调队列斜率优化维护上凸壳就可以了
-
注意先删去较劣的队头后删去较劣的队尾
-
还有这题删劣决策点的符号很奇怪,我也不太懂
-
你听说什么是如出一辙吗,推荐试下找不同
code
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 1000005
#define mod 1000000007
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define O3 __attribute__((optimize("-O3")))
using namespace std;
ll a[MAXN],f[MAXN],pre[MAXN],que[MAXN];
ll n,A,B,C;
O3 inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
O3 inline ll sqr(ll x)
{
return x*x;
}
O3 inline double slope(ll x,ll y)
{
return 1.0*(f[x]+A*sqr(pre[x])-f[y]-A*sqr(pre[y])-B*(pre[x]-pre[y]))/(2.0*A*(pre[x]-pre[y]));
}
O3 int main()
{
//freopen("T3.in","r",stdin);
n=read(),A=read(),B=read(),C=read();
fo(i,1,n)pre[i]=pre[i-1]+(a[i]=read());
ll head=1,tail=1;f[0]=que[1]=0;
fo(i,1,n)
{
while (head<tail && slope(que[head],que[head+1])<=pre[i])++head;
f[i]=f[que[head]]+A*sqr(pre[i]-pre[que[head]])+B*(pre[i]-pre[que[head]])+C;
while (head<tail && slope(que[tail-1],que[tail])>=slope(que[tail],i))--tail;
que[++tail]=i;
}
printf("%lld\n",f[n]);
return 0;
}