Problem
【APIO2010】特别行动队
TimeLimit:4Sec
MemoryLimit:64MB
Description
![](https://www.lydsy.com/JudgeOnline/images/1911_1.jpg)
![](https://www.lydsy.com/JudgeOnline/images/1911_2.jpg)
Output
![](https://www.lydsy.com/JudgeOnline/images/1911_3.jpg)
Sample Output
标签:斜率优化DP
Solution
首先易得DP方程:设f[i]为考虑前i人的最大收益,则f[i]=maxj=0i−1{A×(Si−Sj)2+B×(Si−Sj)+C+f[j]}。
那么推一推:
f[i]=j=0maxi−1{A×(Si−Sj)2+B×(Si−Sj)+C+f[j]}=j=0maxi−1{A×Si2−A×Sj2+2A×Si×Sj+B×Si−B×Sj+C+f[j]}=j=0maxi−1{−2ASj×Si+(A×Sj2−B×Sj+f[j])}+A×Si2+B×Si+C
发现中间−2ASj×Si+(A×Sj2−B×Sj+f[j])是一次函数,那么对于两个位置p,q(p<q),若q比p优秀,则有:
Letkp=−2ASp,bpkpSi+bpSi=A×Sp2−B×Sp+f[p]<kqSi+bq≤kq−kpbp−bq
按照此斜率维护单调栈即可。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include <bits/stdc++.h> #define MAX_N 1000000 using namespace std; typedef long long lnt; typedef double dnt; template <class T> inline void read(T &x) { x = 0; int c = getchar(), f = 1; for (; !isdigit(c); c = getchar()) if (c == 45) f = -1; for (; isdigit(c); c = getchar()) (x *= 10) += f*(c-'0'); } int n, que[MAX_N+5], l, r; lnt A, B, C; lnt s[MAX_N+5], k[MAX_N+5], b[MAX_N+5], f[MAX_N+5]; dnt calc(int x, int y) {return (dnt)(b[x]-b[y])/(dnt)(k[y]-k[x]);} int main() { read(n), read(A), read(B), read(C); for (int i = 1, x; i <= n; i++) read(x), s[i] = s[i-1]+x; int l = 0, r = 0; que[0] = 0, b[0] = C; for (int i = 1; i <= n; i++) { while (l < r && calc(que[l], que[l+1]) <= s[i]) l++; f[i] = k[que[l]]*s[i]+b[que[l]]+A*s[i]*s[i]+B*s[i]; k[i] = -2*A*s[i], b[i] = A*s[i]*s[i]-B*s[i]+C+f[i]; while (l < r && calc(que[r], i) <= calc(que[r-1], que[r])) r--; que[++r] = i; } return printf("%lld\n", f[n]), 0; }
|