[ APIO 2010 ] 特别行动队

本文探讨了一种算法问题,旨在通过动态规划和单调队列优化策略,找到一组人员配置下能达到的最高战斗力。问题设定了一系列数学约束条件,包括线性方程和二次方程的组合,要求在特定范围内寻找最佳解。解决方案首先统计累积值,然后通过状态转移方程和抽象点的概念,将问题转化为直线方程形式,最终利用单调队列维护上凸包,实现高效求解。

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

\(\\\)

Description


5bea08ea3b1fc.png

  • \(N\le 10^6,–5 ≤ a ≤ –1,|b| ≤ 10^7,|c| ≤ 10^7,1 ≤ x_i ≤ 100\)

\(\\\)

Solution


首先统计出 \(s[n]=\sum_{i=1}^nx_i\)

\(f[i]\) 为前 \(i\) 个人可以达到的最高战斗力,易得转移
\[ f[i]=f[j]+a(s[i]-s[j])^2+b(s[i]-s[j])+c \]
列出直线方程的形式
\[ f[j]+as[j]^2-bs[j]=f[i]-as[i]^2-bs[i]-c+2as[i]s[j] \]
容易发现抽象的点就是 \((s[j],f[j]+as[j]^2-bs[j])\)

\(\\\)

\(t[i]=as[i]^2-bs[i]\)

当一个状态下 \(k\)\(j\) 优,有
\[ f[k]+as[k]^2-bs[k]-2as[i]s[k]> f[j]+as[j]^2-bs[j]-2as[i]s[j] \]
整理,化简得
\[ f[k]+t[k]-f[j]-t[j]>2as[i](s[k]-s[j]) \]

\[ \frac{f[k]+t[k]-f[j]-t[j]}{s[k]-s[j]}>2as[i] \]

注意分母除过去的时候需要是正数。

注意直线的斜率 \(2as[i]\) 是负数,且不断变小,可以用单调队列维护了。

同样因为直线的斜率为负数,所以我们需要维护上凸包。

\(\\\)

Code


#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define gc getchar
#define R register
#define N 1000010
using namespace std;
typedef long long ll;

inline ll rd(){
  ll x=0; bool f=0; char c=gc();
  while(!isdigit(c)){if(c=='-')f=1;c=gc();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
  return f?-x:x;
}

ll n,m,a,b,c,s[N],t[N],g[N],q[N],hd,tl,f[N];

inline double calck(ll x,ll y){
  return (double)(f[x]+t[x]-f[y]-t[y])/(double)(s[x]-s[y]);
}

inline ll w(ll x,ll y){
  return f[x]+t[x]+g[y]-2*a*s[x]*s[y];
}

int main(){
  n=rd();
  a=rd(); b=rd(); c=rd();
  for(R ll i=1;i<=n;++i){
    s[i]=s[i-1]+rd();
    t[i]=a*s[i]*s[i]-b*s[i];
    g[i]=a*s[i]*s[i]+b*s[i]+c;
  }
  q[hd=tl=1]=0;
  for(R int i=1;i<=n;++i){
    while(hd<tl&&calck(q[hd+1],q[hd])>2.0*a*s[i]) ++hd;
    f[i]=w(q[hd],i);
    while(hd<tl&&calck(q[tl],q[tl-1])<calck(i,q[tl])) --tl;
    q[++tl]=i;
  }
  printf("%lld\n",f[n]);
  return 0;
}

转载于:https://www.cnblogs.com/SGCollin/p/9950288.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值