P3628 [APIO2010]特别行动队

\(\color{#0066ff}{ 题目描述 }\)

你有一支由 \(n\) 名预备役士兵组成的部队,士兵从 \(1\) 到 \(n\) 编号,要将他们拆分 成若干特别行动队调入战场。出于默契的考虑,同一支特别行动队中队员的编号 应该连续,即为形如\((i, i + 1, ..., i + k)\)的序列。 编号为 i 的士兵的初始战斗力为 xi ,一支特别行动队的初始战斗力 x 为队内 士兵初始战斗力之和,即 \(x = x_i + x_{i+1} + ... + x_{i+k}\)

通过长期的观察,你总结出一支特别行动队的初始战斗力 \(x\) 将按如下经验公 式修正为 \(x':x'= ax^2+bx+c\)其中 \(a, b, c\) 是已知的系数\((a < 0)\)。 作为部队统帅,现在你要为这支部队进行编队,使得所有特别行动队修正后 战斗力之和最大。试求出这个最大和。

例如,你有 4 名士兵, \(x_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\),没有其它 方案能使修正后的战斗力和更大。

\(\color{#0066ff}{输入格式}\)

输入由三行组成。第一行包含一个整数 \(n\),表示士兵的总数。第二行包含三 个整数 \(a, b, c\),经验公式中各项的系数。第三行包含 \(n\) 个用空格分隔的整数 \(x_1, x_2, …, x_n\),分别表示编号为 \(1, 2, …, n\) 的士兵的初始战斗力。

\(\color{#0066ff}{输出格式}\)

输出一个整数,表示所有特别行动队修正后战斗力之和的最大值。

\(\color{#0066ff}{输入样例}\)

4
-1 10 -20
2 2 3 4 

\(\color{#0066ff}{输出样例}\)

9

\(\color{#0066ff}{数据范围与提示}\)

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

\(\color{#0066ff}{题解}\)

不难得出DP式子

\(f[i]\)代表\(1\to i\)分组的答案, \(s[i]\)代表每个人x的前缀和

则\(f[i] = f[j-1] + a*(s[i]-s[j-1])^2+b*(s[i]-s[j-1])+c\)

\(f[i]=f[j-1]+a*s[i]^2+a*s[j-1]^2-2*a*s[i]*s[j-1]+b*s[i]-b*s[j-1]+c\)

\(f[i]=f[j-1]+a*s[j-1]^2-2*a*s[i]*s[j-1]-b*s[j-1]+a*s[i]^2+b*s[i]+c\)

令\(t=a*s[i]^2+b*s[i]+c\)

\(f[i]=f[j-1]+a*s[j-1]^2-(2*a*s[i]+b)*s[j-1]\)

令\(k(斜率)=(2*a*s[i]+b)\)

\(k*s[j-1]+f[i]=f[j-1]+a*s[j-1]^2+t\)

看成平面上的点\((s[j-1],f[j-1]+a*s[j-1]^2)\),t最后加就行了

f[i]作为直线的截距,我们要找最大截距,即维护上凸包

虚线即当前斜率k

则当且仅当k在两个斜率之间的那个交点处最优

取到最优点后,再维护凸包

可以用双端队列

#include<bits/stdc++.h>
#define LL long long
LL in() {
    char ch; int x = 0, f = 1;
    while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    return x * f;
}
const int maxn = 1e6 + 100;
const LL inf = 999999999999999LL;
LL f[maxn], s[maxn], a, b, c;
int n;
int head, tail, q[maxn];
LL X(int x) { return s[x]; }
LL Y(int x) { return f[x] + a * s[x] * s[x]; }
double k(int x, int y) { return (double)(Y(x) - Y(y)) / (double)(X(x) - X(y)); }
int main() {
    n = in(), a = in(), b = in(), c = in();
    for(int i = 1; i <= n; i++) s[i] = s[i - 1] + in();
    for(int i = 1; i <= n; i++) {
        LL K = 2LL * a * s[i] + b;
        LL t = a * s[i] * s[i] + b * s[i] + c;
        while(head < tail && K < k(q[head + 1], q[head])) head++;
        f[i] = Y(q[head]) + t - K * X(q[head]);
        while(head < tail && k(q[tail], q[tail - 1]) < k(q[tail], i)) tail--;
        q[++tail] = i;
    }
    printf("%lld\n", f[n]);
    return 0;
}

原文地址:https://www.cnblogs.com/olinr/p/10227075.html

时间: 2024-10-10 23:46:43

P3628 [APIO2010]特别行动队的相关文章

Bzoj1911 [Apio2010]特别行动队

1911: [Apio2010]特别行动队 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 3969  Solved: 1873 Description Input Output Sample Input 4 -1 10 -20 2 2 3 4 Sample Output 9 HINT Source 斜率优化DP f[分组末尾]=最优解 f[i] = max{f[j]+A(s[i]-s[j])^2+B(s[i]-s[j])+C}  (0<=j<i)

APIO2010特别行动队(单调队列、斜率优化)

其实这题一看知道应该是DP,再一看数据范围肯定就是单调队列了. 不过我还不太懂神马单调队列.斜率优化-- 附上天牛的题解:http://www.cnblogs.com/neverforget/archive/2012/04/19/2456483.html 1 var f,g:array[0..1000050] of int64; 2 s,q:array[0..1000050] of longint; 3 a,b,c,n,i,h,t,x:longint; 4 bestk:double; 5 pro

BZOJ 1911: [Apio2010]特别行动队 [斜率优化DP]

1911: [Apio2010]特别行动队 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 4142  Solved: 1964[Submit][Status][Discuss] Description Input Output Sample Input 4 -1 10 -20 2 2 3 4 Sample Output 9 HINT f[i]=max{f[j]+...} 随便一化就好了 (a*(s[k]*s[k]-s[j]*s[j])+f[k]-f[

[Apio2010]特别行动队

1911: [Apio2010]特别行动队 Time Limit: 4 Sec  Memory Limit: 64 MB[Submit][Status][Discuss] Description Input Output Sample Input 4 -1 10 -20 2 2 3 4 Sample Output 9 HINT 斜率优化的式子搞出来之后,a是负的,所以要么不除过去,要么除过去变号 #include<cstdio> #include<iostream> #includ

斜率优化专题4——bzoj 1911: [Apio2010] 特别行动队 题解

[原题] 1911: [Apio2010]特别行动队 Time Limit: 4 Sec  Memory Limit: 64 MB Submit: 2134  Solved: 911 [Submit][Status] Description Input Output Sample Input 4 -1 10 -20 2 2 3 4 Sample Output 9 HINT [分析]只要跟着我前面的题目走,这道题真的是太水了.神马题解都不用参考,公式随便推. 易知方程是f[i]=max(f[j]+

bzoj 1911 [Apio2010]特别行动队(斜率优化+DP)

1911: [Apio2010]特别行动队 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 3191  Solved: 1450[Submit][Status][Discuss] Description Input Output Sample Input 4 -1 10 -20 2 2 3 4 Sample Output 9 HINT Source [思路] 斜率优化. 设f[i]表示将前i个分组的最优值,则有转移方程式: f[i]=max{ f[j]

BZOJ 1911: [Apio2010]特别行动队( dp + 斜率优化 )

sum为战斗力的前缀和 dp(x) = max( dp(p)+A*(sumx-sump)2+B*(sumx-sump)+C )(0≤p<x) 然后斜率优化...懒得写下去了... -------------------------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; typedef long long ll; const in

【BZOJ1911】[Apio2010]特别行动队 斜率优化DP

想了好久啊.... 用了我感觉比较好写的一种(因为没写过维护凸包),另一种是维护凸包的做法,本质一样?推荐http://www.mamicode.com/info-detail-345781.html. 网上的大多数解法: DP:f[i]=max(f[j]+a*(sum[i]-sum[j])^2+b(sum[i]-sum[j])+c) 显然复杂度不对. 那么假设j>k且f[j]优于f[k] f[j]-f[k]+a*(sum[j]^2-sum[k]^2)-b*(sum[j]-sum[k])>2*

bzoj1911[Apio2010]特别行动队 斜率优化dp

1911: [Apio2010]特别行动队 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 5057  Solved: 2492[Submit][Status][Discuss] Description Input Output Sample Input 4 -1 10 -20 2 2 3 4 Sample Output 9 HINT dp[i]=dp[j]+a*x*x+b*x+cx=sum[i]-sum[j] 证明单调性假设对于i点 k<j且j的决策