bzoj3156 防御准备
题意
题解
设 $f[i]$ 表示在第 $i$ 个点建一个塔,$1$ 到 $i$ 都完成的最小代价。
我们可以得到:
$$f[i]=\min_{j=1}^{i-1}\left(f[j]+a_i+\sum_{k=j+1}^{i-1}\left(i-k\right)\right)$$
由于 $i-i=0$,所以我们变形
$$f[i]=\min_{j=1}^{i-1}\left(f[j]+a_i+\sum_{k=j+1}^{i}\left(i-k\right)\right)$$
然后我们展开,假设 $f[i]$ 在 $j$ 点取得最小值,$sum[i]$ 表示 $1+\cdots+i$,
$$f[i]=f[j]+a_i+(i-j)i-sum[i-1]+sum[j]$$
我们展开,移项,得
$$f[j]+sum[j]=f[i]+sum[i-1]-a_i-(i-j)i$$
在 $sum[i-1]$ 中加上一个 $i$ 然后再减,得到
$$f[j]+sum[j]=f[i]+sum[i]-i-a_i-i^2-ij$$
然后就可以用斜率优化了。$h(i)=f[i]+sum[i]$。
调试记录
- 没开 long long
- 前缀和错误
代码
#include <bits/stdc++.h> using namespace std; #define int long long int n; int a[1000005], f[1000005], sum[1000005], q[1000005]; inline int h(int i) { return f[i] + sum[i]; } signed main() { scanf("%lld", &n); sum[0] = 0; for (int i=1; i<=n; i++) { scanf("%lld", &a[i]); sum[i] = sum[i-1] + i; } f[0] = 0; int l = 0, r = 0; for (int i=1; i<=n; i++) { while (l < r && h(q[l+1]) - h(q[l]) < (q[l+1] - q[l]) * i) ++l; f[i] = h(q[l]) - q[l] * i + i * i + a[i] - sum[i]; while (l < r && (h(i) - h(q[r])) * (q[r] - q[r-1]) < (i - q[r]) * (h(q[r]) - h(q[r-1]))) --r; q[++r] = i; } printf("%lld\n", f[n]); return 0; }