1. 程式人生 > >bzoj1911: [Apio2010]特別行動隊

bzoj1911: [Apio2010]特別行動隊

ble href api www. || urn algo printf \n

題目鏈接

bzoj1911: [Apio2010]特別行動隊

題解

首先,狀態轉移方程
\(f_i = max(f_j+A(S_i-S_j)^2+B(S_i-S_j)+C)\)
在這裏總結一下推斜率優化的兩種方法吧

直接推呀:

\(j<k\)\(j\)\(k\)優。
\[f_j+A(S_i-S_j)^2+B(S_i-S_j)+C>f_k+A(S_i-S_k)^2+B(S_i-S_k)+C\]
\[f_j-f_k+A(2S_i-S_j-S_k)*(S_k-S_j)+B(S_k-S_j)>0\]
\[f_j+S_j^2-2AS_iS_j-BS_j >f_k+S_k^2-2AS_iS_k-BS_k\]


\(G_j=f_j+AS_j^2-BS_j\),\(H_j=-2AS_j\)
得到
\(\frac{G_j-G_k}{H_j-H_k}<-S_i\)

找直線解析式

技術分享圖片

代碼

#include<cstdio> 
#include<cstring> 
#include<algorithm> 
#define LL long long
inline LL read() { 
    LL x = 0,f = 1;
    char c = getchar(); 
    while(c < '0' || c > '9'
){ if(c == '-')f = -1; c = getchar();} while(c <= '9' && c >= '0')x = x * 10 + c - '0',c = getchar(); return x * f; } const int maxn = 1000007; LL n,a,b,c; LL sum[maxn]; LL dp[maxn]; LL Y (int i) { return dp[i] + a * sum[i] * sum[i] - b * sum[i]; } LL X (int
i) { return sum[i]; } double slop(int i,int j) { return 1.0 * (Y(i) - Y(j)) / (X(i) - X(j)); } int q[maxn]; int main() { n = read(),a = read(),b = read(),c = read(); for(int i = 1;i <= n;++ i) sum[i] = read() + sum[i - 1]; for(int l = 0,r = 0,i = 1;i <= n;++ i) { while(l < r && slop(q[l],q[l + 1]) > 2 * a * sum[i])l ++; //dp[i] = dp[q[l]] + a * (sum[i] - sum[q[l]]) * (sum[i] - sum[q[l]]) + b * (sum[i] - sum[q[l]] + c); dp[i] = -(2 * a * sum[i] * X(q[l]) - Y(q[l]) - a * sum[i] * sum[i] - b * sum[i] - c); while(l < r && slop(q[r - 1],q[r]) <= slop(q[r],i)) r --; q[++ r] = i; } printf("%lld\n",dp[n]); return 0; }

bzoj1911: [Apio2010]特別行動隊