斜率优化DP
dp[i][j]表示前i个仓库爆炸j次得到的最小值
dp[i][j] = min(dp[k][j]+w[k+1, i]) (j <= k < i)方程的意思是表示第j次爆炸发生在第k段铁路
w[l, r]表示从第l个仓库到第r个仓库所得的Strategic Value
设a[i]表示第i个仓库的价值
w[l, r] = ∑( ∑a[i]*a[j] (i < j <= r)) (l <= i <= r)
设s[i] = ∑a[k] (1 <= k <= i)
as[i] = ∑a[k]*s[k] (1 <= k <= i)
则有w[l, r] = s[r]*(s[r]-s[l-1])-(as[r]-as[l-1])
dp[k][j]+w[k+1, i] = dp[k][j]+s[i]*(s[i]-s[k])-(as[i]-as[k])
dp[i][j] = min(dp[k][j]+as[k]-s[i]*s[k])+s[i]*s[i]-as[i]
用y表示dp[k][j]+as[k],x表示s[k],a表示s[i]
有G = -ax+y,a单调递增,编程了斜率优化的标准形式,不过需要维护m个队列
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <queue> #include <algorithm> #include <vector> #include <cstring> #include <stack> #include <cctype> #include <utility> #include <map> #include <string> #include <climits> #include <set> #include <string> #include <sstream> #include <utility> #include <ctime> #include <bitset> using std::priority_queue; using std::vector; using std::swap; using std::stack; using std::sort; using std::max; using std::min; using std::pair; using std::map; using std::string; using std::cin; using std::cout; using std::set; using std::queue; using std::string; using std::stringstream; using std::make_pair; using std::getline; using std::greater; using std::endl; using std::multimap; using std::deque; using std::unique; using std::lower_bound; using std::random_shuffle; using std::bitset; using std::upper_bound; using std::multiset; typedef long long LL; typedef unsigned long long ULL; typedef pair<int, int> PAIR; typedef multimap<int, int> MMAP; typedef LL TY; typedef long double LF; const int MAXN(1000010); const int MAXM(100010); const int MAXE(100010); const int MAXK(6); const int HSIZE(31313); const int SIGMA_SIZE(26); const int MAXH(19); const int INFI((INT_MAX-1) >> 1); const ULL BASE(31); const LL LIM(10000000); const int INV(-10000); const int MOD(20100403); const double EPS(1e-7); const LF PI(acos(-1.0)); template<typename T> void checkmax(T &a, T b){if(b > a) a = b;} template<typename T> void checkmin(T &a, T b){if(b < a) a = b;} template<typename T> T ABS(const T &a){return a < 0? -a: a;} int arr[1010]; LL sum[1010]; LL as[1010]; LL table[1010][1010]; int que[1010][1010]; int front[1010], back[1010]; LL Y(int ind1, int ind2){ return table[ind1][ind2]+as[ind1];} LL X(int ind){ return sum[ind];} int main() { int n, m; while(scanf("%d%d", &n, &m), n+m) { for(int i = 1; i <= n; ++i) { scanf("%d", arr+i); sum[i] = sum[i-1]+arr[i]; as[i] = as[i-1]+arr[i]*sum[i]; } for(int i = 0; i <= m; ++i) { front[i] = 0; back[i] = -1; } for(int i = 1; i <= n; ++i) { int lim = min(m, i-1); LL a = sum[i]; LL temp = sum[i]*sum[i]-as[i]; for(int j = lim; j > 0; --j) { while(back[j-1]-front[j-1] > 0 && (-a)*X(que[j-1][front[j-1]+1])+Y(que[j-1][front[j-1]+1], j-1) <= (-a)*X(que[j-1][front[j-1]])+Y(que[j-1][front[j-1]], j-1)) ++front[j-1]; table[i][j] = (-a)*X(que[j-1][front[j-1]])+Y(que[j-1][front[j-1]], j-1)+temp; while(back[j]-front[j] > 0 && (Y(i, j)-Y(que[j][back[j]-1], j))*(X(i)-X(que[j][back[j]])) >= (Y(i, j)-Y(que[j][back[j]], j))*(X(i)-X(que[j][back[j]-1]))) --back[j]; que[j][++back[j]] = i; } table[i][0] = sum[i]*(sum[i]-sum[0])-(as[i]-as[0]); while(back[0]-front[0] > 0 && (Y(i, 0)-Y(que[0][back[0]-1], 0))*(X(i)-X(que[0][back[0]])) >= (Y(i, 0)-Y(que[0][back[0]], 0))*(X(i)-X(que[0][back[0]-1]))) --back[0]; que[0][++back[0]] = i; } printf("%I64d\n", table[n][m]); } return 0; }