[APIO2010]特别行动队

传送门

\(dp[i]\)表示到第i个士兵的最大战斗值,则有:

\(dp[i] = max_{j=1}^{i-1}\{dp[j] + f(sum[i] - sum[j])\}\),其中\(f(x) = ax^2 + bx + c\)

把式子拆开以后用斜率优化即可。因为作为标准的常量是\(sum[i]\),保持单调递增,直接优化即可。

注意,使用宏定义一定要被运算的参数打上括号……否则会出现神奇的结果……

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
#define f(i) (dp[i] - bsum[i] + asum[i])
#define g(i) (a * i * i + b * i + c)
#define h(i) (2 * a * sum[i])
using namespace std;
typedef long long ll;
const int M = 1000005;
const int N = 10000005;
 
ll read()
{
   ll ans = 0,op = 1;char ch = getchar();
   while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
   while(ch >='0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
   return ans * op;
}

ll a,b,c,n,dp[M],q[M],head,tail,x[M],sum[M],asum[M],bsum[M];

double slope(ll p,ll q)
{
   return 1.0 * (f(p) - f(q)) / (sum[p] - sum[q]);
}

int main()
{
   n = read(),a = read(),b = read(),c = read();
   rep(i,1,n)
   {
      x[i] = read(),sum[i] = sum[i-1] + x[i];
      bsum[i] = sum[i] * b,asum[i] = a * sum[i] * sum[i];
   }
   rep(i,1,n)
   {
      while(head < tail && slope(q[head],q[head+1]) > h(i)) head++;
      dp[i] = dp[q[head]] + g((sum[i] - sum[q[head]]));
      //dp[i] = f(q[head]) - h(i) * sum[q[head]] + g(sum[i]);
      while(head < tail && slope(q[tail-1],q[tail]) <= slope(q[tail],i)) tail--;
      q[++tail] = i;
   }
   printf("%lld\n",dp[n]);
   return 0;
}

posted @ 2018-12-21 15:22  CaptainLi  阅读(113)  评论(0编辑  收藏  举报