特别行动队
Posted wscqwq
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了特别行动队相关的知识,希望对你有一定的参考价值。
题目传送门
其实这题直接推式子,不需要转换,还是很简单的。
考虑用 \\(f_i\\) 表示前 \\(i\\) 名士兵修正战斗力之和的最大值。令 \\(X=sum_i-sum_j\\),易得 \\(f_i=f_j+aX^2+bX+c\\)。
将 \\(X=sum_i-sum_j\\) 代入得 \\(f_i=f_j+a(sum_i-sum_j)^2+b(sum_i-sum_j)+c\\)。其中 \\(i\\) 是常量。展开得 \\(f_i=f_j+asum_i^2+asum_j^2-2asum_isum_j+bsum_i-bsum_j+c\\)
求 \\(\\max b\\)。
\\(k\\) 递减,\\(x\\) 递增
维护一个上凸包即可。
#include<bits/stdc++.h>
using namespace std;
#define L(i,l,r) for(int i=l;i<=r;++i)
#define R(i,l,r) for(int i=r;i>=l;--i)
const int N=1000010;
int n,sum[N],q[N];
typedef long long ll;
ll f[N],a,b,c;
#define y(j) (f[j]+a*sum[j]*sum[j]-b*sum[j])
namespace IO
int len=0;
char ibuf[(1<<20)+1],*iS,*iT,out[(1<<25)+1],ar[50];
#define gh()\\
(iS==iT?iT=(iS=ibuf)+fread(ibuf,1,(1<<20)+1,stdin),\\
(iS==iT?EOF:*iS++):*iS++)
void read()
template<typename Type,typename...Types>
void read(Type&x,Types&...xs)
char ch=gh();
char t=0;
while(ch<\'0\'||ch>\'9\')t|=ch==\'-\',ch=gh();
while(ch>=\'0\'&&ch<=\'9\')x=x*10+(ch^48),ch=gh();
x=t?-x:x;
read(xs...);
void putc(char ch)out[len++]=ch;
void write(char c)
template<typename Type, typename... Types>
void write(char c,Type&x,Types&...xs)
int tot=0;
if(!x)putc(\'0\');
if(x<0)putc(\'-\'),x=-x;
while(x)ar[++tot]=x%10+\'0\',x/=10;
for(int i=tot;i;--i)putc(ar[i]);
putc(c);
write(c,xs...);
void flush()
fwrite(out,1,len,stdout);
len=0;
using namespace IO;
int main()
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
// ios::sync_with_stdio(0);
// cin.tie(0);
// cout.tie(0);
read(n,a,b,c);
L(i, 1, n)
read(sum[i]);
sum[i]+=sum[i-1];
int hh=0,tt=0;
L(i, 1, n)
while(hh<tt&&(y(q[hh+1])-y(q[hh]))>=2*a*sum[i]*(sum[q[hh+1]]-sum[q[hh]]))++hh;
int j=q[hh],X=sum[i]-sum[j];
f[i]=f[j]+a*X*X+b*X+c;
while(hh<tt&&(y(q[tt])-y(q[tt-1]))*(sum[i]-sum[q[tt]])<=(y(i)-y(q[tt]))*(sum[q[tt]]-sum[q[tt-1]]))--tt;
q[++tt]=i;
printf("%lld",f[n]);
return 0;
[luogu P3628] [APIO2010]特别行动队
[luogu P3628] [APIO2010]特别行动队
题目描述
你有一支由 n 名预备役士兵组成的部队,士兵从 1 到 n 编号,要将他们拆分 成若干特别行动队调入战场。出于默契的考虑,同一支特别行动队中队员的编号 应该连续,即为形如(i, i + 1, ..., i + k)(i,i+1,...,i+k)的序列。 编号为 i 的士兵的初始战斗力为 xi ,一支特别行动队的初始战斗力 x 为队内 士兵初始战斗力之和,即 x = x_i + x_{i+1} + ... + x_{i+k}x=x?i??+x?i+1??+...+x?i+k??。
通过长期的观察,你总结出一支特别行动队的初始战斗力 x 将按如下经验公 式修正为 $x‘:x‘ = ax2 + bx + c$,其中 a, b, c 是已知的系数(a < 0)。 作为部队统帅,现在你要为这支部队进行编队,使得所有特别行动队修正后 战斗力之和最大。试求出这个最大和。
例如,你有 4 名士兵, x_1 = 2, x_2 = 2, x_3 = 3, x_4 = 4x?1??=2,x?2??=2,x?3??=3,x?4??=4。经验公式中的参数为 a = –1, b = 10, c = –20。此时,最佳方案是将士兵组成 3 个特别行动队:第一队包含士兵 1 和士兵 2,第二队包含士兵 3,第三队包含士兵 4。特别行动队的初始战斗力分 别为 4, 3, 4,修正后的战斗力分别为 4, 1, 4。修正后的战斗力和为 9,没有其它 方案能使修正后的战斗力和更大。
输入输出格式
输入格式:
输入由三行组成。第一行包含一个整数 n,表示士兵的总数。第二行包含三 个整数 a, b, c,经验公式中各项的系数。第三行包含 n 个用空格分隔的整数 $x_1, x_2, …, x_n$,分别表示编号为 1, 2, …, n 的士兵的初始战斗力。
输出格式:
输出一个整数,表示所有特别行动队修正后战斗力之和的最大值。
输入输出样例
4
-1 10 -20
2 2 3 4
9
说明
20%的数据中,n ≤ 1000;
50%的数据中,n ≤ 10,000;
100%的数据中,1 ≤ n ≤ 1,000,000,–5 ≤ a ≤ –1,|b| ≤ 10,000,000,|c| ≤ 10,000,000,1 ≤ xi ≤ 100。
斜率DP pro 2。相比上一题,本蒟蒻感觉这题水多了,只是调了一下才A。
设f[i]为前i个人的战斗力最大值,s[i]为前i个人战斗力的和。易得:
f[i]=max{f[j]+a(s[i]-s[j])^2+b(s[i]-s[j])+c}(j<i)
=max{f[j]+as[i]^2-2as[i]s[j]+as[j]^2+bs[i]-bs[j]+c}
设X[i]=as[i]^2,Y[i]=bs[i],则原式
=max{f[j]+X[i]-2as[i]s[j]+X[j]+Y[i]-Y[j]+c}
设P[i]=X[i]+Y[i],Q[i]=X[i]-Y[i],则原式
=max{f[j]+P[i]+Q[i]-2as[i]s[j]+c}
则f[i]=?f[j]+P[i]+Q[i]-2as[i]s[j]+c
则在这个式子里,y=f[j]+Q[j],k=2as[i],x=s[j],b=f[i]-P[i]-c,且y=kx+b。
由于是取max,所以是维护一个上凸包,所以维护一个斜率只降不升的单调队列就可以了。
其中每个点的坐标为(xi,yi)=(s[i],f[i]+Q[i])(可以从最后那个x和y的表达式看出来)。
code:
1 %:pragma GCC optimize(2) 2 #include<bits/stdc++.h> 3 #define sqr(x) ((x)*(x)) 4 #define LL long long 5 using namespace std; 6 const int N=1000005; 7 const double inf=1e18; 8 int n,l,r; LL A,B,C,ratio,s[N],X[N],Y[N],P[N],Q[N],f[N]; 9 struct point { 10 LL x,y; 11 point() {} 12 point(LL _x,LL _y):x(_x),y(_y) {} 13 }st[N]; 14 inline int read() { 15 int x=0,f=1; char ch=getchar(); 16 while (ch<‘0‘||ch>‘9‘) f=(ch==‘-‘)?-1:1,ch=getchar(); 17 while (ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar(); 18 return x*f; 19 } 20 double slope(point u,point v) { 21 return u.x==v.x?(u.y<v.y?inf:-inf):1.0*(v.y-u.y)/(v.x-u.x); 22 } 23 LL get(LL k) { 24 while (l<r&&slope(st[l],st[l+1])>1.0*k) l++; 25 return st[l].y-k*st[l].x; 26 } 27 void insert(point cur) { 28 while (l<r&&slope(st[r-1],st[r])<slope(st[r-1],cur)) r--; 29 st[++r]=cur; 30 } 31 int main() { 32 n=read(),A=read(),B=read(),C=read(),ratio=A*2,s[0]=0; 33 for (int i=1; i<=n; i++) s[i]=s[i-1]+read(); 34 for (int i=1; i<=n; i++) X[i]=A*sqr(s[i]); 35 for (int i=1; i<=n; i++) Y[i]=B*s[i]; 36 for (int i=1; i<=n; i++) P[i]=X[i]+Y[i]; 37 for (int i=1; i<=n; i++) Q[i]=X[i]-Y[i]; 38 l=1,r=0,st[++r]=point(0,0); 39 for (int i=1; i<=n; i++) { 40 f[i]=get(ratio*s[i])+P[i]+C; 41 insert(point(s[i],f[i]+Q[i])); 42 } 43 printf("%lld\n",f[n]); 44 return 0; 45 }
以上是关于特别行动队的主要内容,如果未能解决你的问题,请参考以下文章