[关闭]
@ZCDHJ 2019-10-04T09:27:29.000000Z 字数 1007 阅读 504

JSOI2011 柠檬

DP


首先,最优的划分方案每个区间取的数必然是区间两端的数。那么就是很显然的斜率优化 DP。

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cmath>
  4. #include <vector>
  5. typedef long long LL;
  6. #define int LL
  7. const int MAXN = 1e5;
  8. int n;
  9. int a[MAXN | 1], dp[MAXN | 1], sum[MAXN | 1], lst[10005];
  10. std::vector < int > s[10005];
  11. inline int read() {
  12. register int x = 0;
  13. register char ch = getchar();
  14. while (!isdigit(ch)) ch = getchar();
  15. while (isdigit(ch)) {
  16. x = x * 10 + ch - '0';
  17. ch = getchar();
  18. }
  19. return x;
  20. }
  21. inline double slope(int x, int y) {
  22. return 1.0 * (dp[x - 1] + sum[x] * sum[x] * a[x] - dp[y - 1] - sum[y] * sum[y] * a[y]) / (a[x] * sum[x] - a[y] * sum[y]);
  23. }
  24. signed main() {
  25. n = read();
  26. for (int i = 1; i <= n; ++i) {
  27. a[i] = read();
  28. sum[i] = sum[lst[a[i]]] + 1;
  29. lst[a[i]] = i;
  30. }
  31. for (int i = 1; i <= n; ++i) {
  32. while (s[a[i]].size() >= 2 && slope(s[a[i]][s[a[i]].size() - 2], s[a[i]][s[a[i]].size() - 1]) <= slope(s[a[i]][s[a[i]].size() - 1], i)) s[a[i]].pop_back();
  33. s[a[i]].push_back(i);
  34. while (s[a[i]].size() >= 2 && slope(s[a[i]][s[a[i]].size() - 2], s[a[i]][s[a[i]].size() - 1]) <= 2 * (sum[i] + 1)) s[a[i]].pop_back();
  35. int j = s[a[i]].back();
  36. dp[i] = dp[j - 1] + a[i] * (sum[i] - sum[j] + 1) * (sum[i] - sum[j] + 1);
  37. }
  38. printf("%lld\n", dp[n]);
  39. return 0;
  40. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注