特别行动队题解

Posted ljk123-de-bo-ke

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了特别行动队题解相关的知识,希望对你有一定的参考价值。

特别行动队题解

刷水题什么的最愉快了。
题意十分明了,就是选出一种分配方案将士兵分为若干组,使修正后的战斗力最大。
我们先可以写出暴力dp转移:
\\(f[n]\\)为将前\\(i\\)个士兵分组,且第\\(i\\)个士兵为最后一组最后一个的最大战斗力。
\\(f[i]=max_j=1^j<if[j]+a*\\sum_k=j+1^k<=ix[k] *\\sum_k=j+1^k<=ix[k] +b*\\sum_k=j+1^k<=ix[k] +c\\)
时间复杂度:\\(O(n^3)\\)
设前缀和\\(sum[i]=\\sum_j=1^j<=ix[j]\\)
则化为:\\(f[i]=max_j=1^j<if[j]+a*(sum[i]-sum[j])*(sum[i]-sum[j])+b*(sum[i]-sum[j])+c\\)
最后斜率优化一下:
拆开平方,移项:
\\(f[i]-a*sum[i]*sum[i]-b*sum[i]-c+2*sum[i]*sum[j]=f[j]+a*sum[j]*sum[j]-b*sum[j]\\)
其中:
\\(\\bullet y=f[j]+a*sum[j]*sum[j]-b*sum[j]\\)
\\(\\bullet k=2*sum[i]\\)
\\(\\bullet x=sum[j]\\)
\\(\\bullet b=f[i]-a*sum[i]*sum[i]-b*sum[i]-c\\)
\\(\\therefore f[i]=y-kx+a*sum[i]*sum[i]+b*sum[i]+c\\)
技术图片
代码:

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
const int N=1000006;
int n,head=1,tail=1;
ll f[N],sum[N],ans=0,a,b,c,t;
struct pointll x,y;tmp,q[N];
inline int read()
   int T=0,F=1; char ch=getchar();
   while(ch<'0'||ch>'9')if(ch=='-') F=-1; ch=getchar();
   while(ch>='0'&&ch<='9') T=(T<<3)+(T<<1)+(ch-48),ch=getchar();
   return F*T; 

bool check(point u,point v,int z)return v.y-u.y>=2*a*sum[z]*(v.x-u.x);
bool check2(point u,point v,point z)return (v.y-u.y)*(z.x-v.x)<=(z.y-v.y)*(v.x-u.x);
int main()
    n=read(),a=read(),b=read(),c=read();
    q[tail].x=0,q[tail].y=0;
    for(int i=1;i<=n;++i)
        t=read(),sum[i]=sum[i-1]+t;
        while(head<tail&&check(q[head],q[head+1],i)) ++head;
        f[i]=a*sum[i]*sum[i]+b*sum[i]+q[head].y-2*a*sum[i]*q[head].x+c,ans=max(ans,f[i]),tmp.x=sum[i],tmp.y=f[i]+a*sum[i]*sum[i]-b*sum[i];
        while(head<tail&&check2(q[tail-1],q[tail],tmp)) --tail;
        q[++tail]=tmp;
     
    printf("%lld\\n",ans);
    return 0;

以上是关于特别行动队题解的主要内容,如果未能解决你的问题,请参考以下文章

题解[APIO2010]特别行动队

BZOJ1911:[Apio2010]特别行动队——题解

BZOJ1911 [Apio2010]特别行动队 - 动态规划 - 斜率优化

BZOJ 1911 [Apio2010]特别行动队

bzoj1911: [Apio2010]特别行动队

P3628 [APIO2010]特别行动队