经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
题解:P7482 不条理狂诗曲
来源:cnblogs  作者:All_Unluck_Beginning  时间:2024/7/22 9:40:15  对本文有异议

题解:P7482 不条理狂诗曲

本题解借鉴 blossom_j 大佬思路,但这位大佬的题解似乎没放正确代码

题意

对于每一个 \(a\) 的子区间 \(a_{l\dots r}\),求选择若干个不连续的数的和的最大值,对答案取模 \(10^{9}+7\)

思路

主要算法:分治。

计算跨过中点 \(mid\) 的区间的 \(f\) 之和。

首先我们可以写一个 DP。\(f_{i,0/1,0/1}\) 表示 DP 已到达 \(i\) 的位置。第一个 \(0/1\) 表示 \(mid\)\(mid+1\) 是否被选择。第二个 \(0/1\) 表示是否选择了第 \(i\) 个元素。

枚举 \(l\) 对所有的 \(r\) 求和:设 \(g_{i,j}=\max\{f_{i,j,0},f_{i,j,1}\}\)。区间 $\left [ l,r \right ] $ 的答案就是 \(\max\{g_{l,0}+\max\{g_{r,0},g_{r,1}\},g_{l,1}+g_{r,0}\}\)

\(g_{l,0}-g_{l,1}\le g_{r,0}-\max\{g_{r,0},g_{r,1}\}\),则必需选择后者。

\(g_{r,0}-\max\{g_{r,0},g_{l,1}\}\) 排序,二分寻找分界点。

代码

  1. #include<bits/stdc++.h>
  2. #define int long long
  3. using namespace std;
  4. const int mod = 1000000007, Maxn = 2 * 1e5 + 10;
  5. int n, a[Maxn], ans = 0, f[Maxn][2][2], g[Maxn][2],sa[Maxn], sb[Maxn];
  6. struct Node {
  7. int date, ID;
  8. } d[Maxn];
  9. bool cmp(Node x, Node y) {
  10. return x.date < y.date;
  11. }
  12. int ask(int x, int l, int r) {
  13. while (l < r) {
  14. int mid = (l + r + 1) >> 1;
  15. if (d[mid].date <= x)l = mid;
  16. else r = mid - 1;
  17. }
  18. return l;
  19. }
  20. void solve(int l, int r) {
  21. if (l == r) {
  22. ans = (ans + a[l]) % mod;
  23. return;
  24. }
  25. int mid = (l + r) >> 1;
  26. f[mid + 1][0][0] = f[mid + 1][0][1] = f[mid + 1][1][0] = 0, f[mid + 1][1][1] = a[mid + 1];
  27. g[mid + 1][0] = f[mid + 1][0][0];
  28. g[mid + 1][1] = f[mid + 1][1][1];
  29. d[mid + 1].ID = mid + 1;
  30. d[mid + 1].date = g[mid + 1][0] - max(g[mid + 1][0], g[mid + 1][1]);
  31. for (int i = mid + 2; i <= r; i++) {
  32. f[i][0][0] = max(f[i - 1][0][0], f[i - 1][0][1]);
  33. f[i][1][0] = max(f[i - 1][1][0], f[i - 1][1][1]);
  34. f[i][0][1] = f[i - 1][0][0] + a[i];
  35. f[i][1][1] = f[i - 1][1][0] + a[i];
  36. g[i][0] = max(f[i][0][0], f[i][0][1]);
  37. g[i][1] = max(f[i][1][0], f[i][1][1]);
  38. d[i].ID = i;
  39. d[i].date = g[i][0] - max(g[i][0], g[i][1]);
  40. }
  41. sort(d + mid + 1, d + r + 1, cmp);
  42. sa[mid] = sb[mid] = sa[r + 1] = sb[r + 1] = 0;
  43. for (int i = mid + 1; i <= r + 1; i++) {
  44. sa[i] = sa[i - 1] + g[d[i].ID][0];
  45. sb[i] = sb[i - 1] + max(g[d[i].ID][0], g[d[i].ID][1]);
  46. }
  47. f[mid][0][0] = f[mid][0][1] = f[mid][1][0] = 0, f[mid][1][1] = a[mid];
  48. g[mid][0] = f[mid][0][0];
  49. g[mid][1] = f[mid][1][1];
  50. int k = ask(g[mid][0] - g[mid][1], mid, r);
  51. ans = (ans + g[mid][0] * (k - mid) % mod + sb[k] + sa[r] - sa[k] + g[mid][1] * (r - k) % mod + mod) % mod;
  52. for (int i = mid - 1; i >= l; i--) {
  53. f[i][0][0] = max(f[i + 1][0][0], f[i + 1][0][1]);
  54. f[i][1][0] = max(f[i + 1][1][0], f[i + 1][1][1]);
  55. f[i][0][1] = f[i + 1][0][0] + a[i];
  56. f[i][1][1] = f[i + 1][1][0] + a[i];
  57. g[i][0] = max(f[i][0][0], f[i][0][1]);
  58. g[i][1] = max(f[i][1][0], f[i][1][1]);
  59. int k = ask(g[i][0] - g[i][1], mid, r);
  60. ans = (ans + g[i][0] * (k - mid) % mod + sb[k] + sa[r] - sa[k] + g[i][1] * (r - k) % mod + mod) % mod;
  61. }
  62. solve(l, mid), solve(mid + 1, r);
  63. }
  64. signed main() {
  65. cin >> n;
  66. for (int i = 1; i <= n; i++)cin >> a[i];
  67. solve(1, n);
  68. cout << ans << '\n';
  69. return 0;
  70. }

原文链接:https://www.cnblogs.com/AUBSwords/p/18315433

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号