3156: 防御准备
可以很容易地写出$dp$方程。
记$dp_i$为在$i$处放一个守卫塔,从$j$处转移,$j+i...i-1$放木偶。$dp_1=a_1$
为了处理$n$处放木偶的情况,咱一直处理到$n+1$。
$dp_i = min\{dp_j + \sum_{k=j+1}^{i-1}(k-j)\}+a_i$
$dp_i=dp_j+\frac{(i-j)(i-j+1)}{2}+a_i$
如果$j$比$k$优,
$2dp_j+(i-j-1)(i-j)<2dp_k+(i-k-1)(i-k)$
不妨设$j>k$,
$\frac{(2dp_j+j^2+j)-(2dp_k+k^2+k)}{j-k}<2i$
让斜率递减就行。
1 #include<cstdio> 2 #include<deque> 3 #include<iostream> 4 using namespace std; 5 inline char nc() { 6 static char b[1<<16],*s=b,*t=b; 7 return s==t&&(t=(s=b)+fread(b,1,1<<16,stdin),s==t)?-1:*s++; 8 } 9 inline void read(int &x) { 10 char b = nc(); x = 0; 11 for (; !isdigit(b); b = nc()); 12 for (; isdigit(b); b = nc()) x = x * 10 + b - ‘0‘; 13 } 14 typedef double db; 15 typedef long long ll; 16 const int N = 1000005; 17 int n, a[N]; 18 ll dp[N]; 19 inline db Y(int i) { 20 return 2.0 * dp[i] + db(i) * i + i; 21 } 22 inline db slope(int l, int r) { 23 return (Y(r) - Y(l)) / (r - l); 24 } 25 int main() { 26 read(n); deque < int > q(1, 1); 27 for (int i = n; i; --i) read(a[i]); 28 dp[1] = a[1]; 29 for (int i = 2; i <= n+1; ++i) { 30 while (q.size() > 1 && slope(q[0], q[1]) < 2 * i) q.pop_front(); 31 int j = q.front(); dp[i] = dp[j] + (i - j) * (i - j - 1ll) / 2 + a[i]; 32 while (q.size() > 1 && slope(q[q.size()-2], q.back()) > slope(q.back(), i)) q.pop_back(); 33 q.push_back(i); 34 } printf("%lld\n", dp[n+1]); 35 return 0; 36 }