题目:

一个斜率优化+CDQ好题

BZOJ2149

分析:

先吐槽一下题意:保留房子反而要给赔偿金是什么鬼哦……

第一问是一个经典问题。直接求原序列的最长上升子序列是错误的。比如\(\{1,2,2,3\}\),选择\(\{1,2,3\}\)不改变后会发现无论如何修改都无法变成一个严格上升序列。只能选择\(\{1,2\}\),把原序列改成\(\{1,2,3,4\}\)。

考虑对于两个数\(a_i\)和\(a_j(j<i)\),\(a_i\)能接在\(a_j\)后面的充要条件是\(a_i-a_j\geq i-j\)(这样中间才能塞下\(i-j-1\)个数形成上升序列)。移项得到\(a_i-i\geq a_j-j\),所以应该把每个数减去它的编号作为权值然后求最长非降子序列。由于要求美观度为正整数,所以若\(a_i-i<0\),则\(i\)不能作为序列的开端。下面的代码展示了\(O(nlog_2n)\)求法(其中\(c[i]=a[i]-i\),\(f[i]\)表示以\(i\)结尾的最长非降子序列的长度)。

int solve()
{int ans = 0;memset(tmp, INF, sizeof(int[n + 1]));for (int i = 1; i <= n; i++){if (c[i] < 0)f[i] = 0;else{int pos = upper_bound(tmp + 1, tmp + ans + 1, c[i]) - tmp;tmp[pos] = c[i];ans = max(ans, pos);f[i] = pos;}v[f[i]].push_back(i);}return ans;
}

然后来看第二问。设\(dp[i]\)为将前\(i\)个数变成单调上升序列的最小总花费。则\(dp[i]\)可以由\(dp[j]\)转移而来的必要条件是\(i>j\),\(a[i]-i>a[j]-j\)且\(f[i]=f[j]+1\)(若\(f[i]>f[j]+1\),则不满足“保留最多的旧房子”;若\(f[i]<f[j]+1\),说明你\(f[i]\)算错了)。

转移时,最优解显然是把\(a[k](j<k<i)\)变成一个以\(a[j]+1\)为首项,公差为\(1\)的等差数列。由于\(a[i]-i>a[j]-j\),所以改完以后一定有\(a[i-1]<a[i]\)

\[dp[i]=min\{dp[j]+\frac{[a[j]+1+a[j]+(i-j-1)]\times(i-j-1)}{2}+a[i]+b[i]\}\]

整理一下,得到:

\[dp[i]=min\{dp[j]+a[j]\times(i-j-1)+\frac{i(i-1)}{2}+\frac{j(j+1)}{2}+-ij+a[i]+b[i]\}\]

可以根据\(f[i]\)分层,一起处理所有\(f[j]=k-1\)的\(j\)对\(f[i]=k\)的\(i\)的贡献。下面考虑每一层的情况。

未完待续……

代码:

方便起见,在序列首加一个\(0\)(\(a[0]=f[0]=0\))。这样可以保证改造后美观度为正(因为\(f[i]=1\)的\(dp[i]\)必然从\(dp[0]\)转移而来);在序列尾加一个无穷大作为\(a[n+1]\),\(dp[n+1]-a[n+1]\)即为答案。

#include <cstdio>
#include <algorithm>
#include <cctype>
#include <cstring>
#include <vector>
using namespace std;namespace zyt
{template<typename T>inline void read(T &x){char c;bool f = false;x = 0;doc = getchar();while (c != '-' && !isdigit(c));if (c == '-')f = true, c = getchar();dox = x * 10 + c - '0', c = getchar();while (isdigit(c));if (f)x = -x;}template<typename T>inline void write(T x){static char buf[20];char *pos = buf;if (x < 0)putchar('-'), x = -x;do*pos++ = x % 10 + '0';while (x /= 10);while (pos > buf)putchar(*--pos);}typedef long long ll;typedef long double ld;const int N = 1e5 + 10, INF = 0x3f3f3f3f;const ll LINF = 0x3f3f3f3f3f3f3f3fLL;int n, a[N], b[N], c[N], f[N], tmp[N];ll dp[N];vector<int> v[N];int solve(){int ans = 0;memset(tmp, INF, sizeof(int[n + 1]));for (int i = 1; i <= n; i++){if (c[i] < 0)f[i] = 0;else{int pos = upper_bound(tmp + 1, tmp + ans + 1, c[i]) - tmp;tmp[pos] = c[i];ans = max(ans, pos);f[i] = pos;}v[f[i]].push_back(i);}v[0].push_back(0);return ans;}inline ll x(const int i){return i - a[i];}inline ll y(const int i){return dp[i] - (ll)(i + 1) * a[i] + (ll)i * (i + 1) / 2;}inline ld ratio(const int i, const int j){if (x(i) == x(j))return y(i) < y(j) ? -LINF : LINF;elsereturn (ld)(y(i) - y(j)) / (x(i) - x(j));}struct node{int pos;bool type;bool operator < (const node &b) const{return pos < b.pos;}}arr[N];const int CHANGE = 0, QUERY = 1;void CDQ(const int l, const int r){if (l == r)return;int mid = (l + r) >> 1, i = l, j = mid + 1, k = l;static node tmp[N];static int st[N];CDQ(l, mid), CDQ(mid + 1, r);int top = 0;while (i <= mid && j <= r){if (x(arr[i].pos) >= x(arr[j].pos)){if (arr[i].type == CHANGE){while (top > 1 && ratio(st[top - 2], st[top - 1]) < ratio(st[top - 1], arr[i].pos))--top;st[top++] = arr[i].pos;}tmp[k++] = arr[i++];}else{if (arr[j].type == QUERY && top){int l = 0, r = top - 2, ans = top - 1;while (l <= r){int mid = (l + r) >> 1;if (ratio(st[mid], st[mid + 1]) < arr[j].pos)r = mid - 1, ans = mid;elsel = mid + 1;}dp[arr[j].pos] = min(dp[arr[j].pos], dp[st[ans]] + (ll)((a[st[ans]] << 1) + arr[j].pos - st[ans]) * (arr[j].pos - st[ans] - 1) / 2+ a[arr[j].pos] + b[arr[j].pos]);}tmp[k++] = arr[j++];}}while (i <= mid)tmp[k++] = arr[i++];while (j <= r){if (arr[j].type == QUERY && top){int l = 0, r = top - 2, ans = top - 1;while (l <= r){int mid = (l + r) >> 1;if (ratio(st[mid], st[mid + 1]) < arr[j].pos)r = mid - 1, ans = mid;elsel = mid + 1;}dp[arr[j].pos] = min(dp[arr[j].pos], dp[st[ans]] + (ll)((a[st[ans]] << 1) + arr[j].pos - st[ans]) * (arr[j].pos - st[ans] - 1) / 2+ a[arr[j].pos] + b[arr[j].pos]);}tmp[k++] = arr[j++];}memcpy(arr + l, tmp + l, sizeof(node[r - l + 1]));}int work(){read(n);for (int i = 1; i <= n; i++)read(a[i]), c[i] = a[i] - i;for (int i = 1; i <= n; i++)read(b[i]);a[++n] = INF;c[n] = INF;int ans = solve();write(ans - 1), putchar(' ');memset(dp, INF, sizeof(ll[n + 1]));dp[0] = 0;for (int i = 1; i <= ans; i++){int cnt = 0;for (int j = 0; j < v[i - 1].size(); j++)if (dp[v[i - 1][j]] < LINF)arr[++cnt] = (node){v[i - 1][j], CHANGE};for (int j = 0; j < v[i].size(); j++)arr[++cnt] = (node){v[i][j], QUERY};sort(arr + 1, arr + cnt + 1);CDQ(1, cnt);}write(dp[n] - a[n] - b[n]);return 0;}
}
int main()
{return zyt::work();
}

转载于:https://www.cnblogs.com/zyt1253679098/p/9966810.html

【BZOJ2149】拆迁队(斜率优化DP+CDQ分治)相关推荐

  1. bzoj2149拆迁队 斜率优化dp+分治

    2149: 拆迁队 Time Limit: 10 Sec  Memory Limit: 259 MB Submit: 397  Solved: 177 [Submit][Status][Discuss ...

  2. BZOJ 2149 拆迁队 斜率优化DP 主席树

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2149 题目大意: 一个长度为 n n的序列aa,改变其中的某些数使之成为一个单调递增序列, ...

  3. P4655-[CEOI2017]Building Bridges【斜率优化dp,CDQ分治】

    正题 题目链接:https://www.luogu.com.cn/problem/P4655 题目大意 nnn座桥,删除第iii座会产生wiw_iwi​的代价,相邻的两座桥i,ji,ji,j会产生(h ...

  4. P4027-[NOI2007]货币兑换【斜率优化dp,CDQ分治】

    正题 题目链接:https://www.luogu.com.cn/problem/P4027 题目大意 nnn天开始时有SSS元钱,每天AAA种股票价格为aia_iai​,BBB种价格为bib_ibi ...

  5. APIO2010 特别行动队 斜率优化DP算法笔记

    做完此题之后 自己应该算是真正理解了斜率优化DP 根据状态转移方程$f[i]=max(f[j]+ax^2+bx+c),x=sum[i]-sum[j]$ 可以变形为 $f[i]=max((a*sum[j ...

  6. 「APIO2010」 特别行动队 - 斜率优化Dp

    题目描述 你有一支由nnn名预备役士兵组成的部队,士兵从1到nnn编号,要将他们拆分成若干特别行动队调入战场.出于默契考虑,同一支特别行动队中队员的编号应该连续,即为形如(i,i+1,...,i+k) ...

  7. 【bzoj1911】[Apio2010]特别行动队 斜率优化dp

    题目描述 输入 输出 样例输入 4 -1 10 -20 2 2 3 4 样例输出 9 题解 斜率优化dp 设f[i]表示前i个士兵的战斗力之和的最大值. 那么有f[i]=f[j]+a*(sum[i]- ...

  8. bzoj 2149 拆迁队 斜率优化+cdq分治

    题面 题目传送门 解法 从来没写过这样的-- 第一问非常简单,能够从 j j j转移到 i i i的条件显然为 a [ i ] − a [ j ] ≥ i − j a[i]-a[j]≥i-j a[i] ...

  9. bzoj1492 货币兑换cash dp斜率优化+splay/cdq分治

    斜率优化 首先,由于如果在i天买在j天卖有利可图,那么最优方法就是在i天花完钱在j天卖完.我们令 f i f_i fi​为第i天可以得到的最多钱数,然后可以先列方程求出花完钱在第j天得到的两种金券数 ...

最新文章

  1. mysql和jdbc的区别_JDBC详解
  2. 素短语,最左素短语-编译原理
  3. JSON——入门语法、对象、数组
  4. 【31】将文件间的编译依存关系降至最低
  5. 引用类型 —— Array类型
  6. 【链表】剑指offer:反转链表
  7. java-JDBC配置驱动程序
  8. [Spring]04_最小化Spring XML配置
  9. LINUX FFMPEG编译汇总(中等,只编译必要的部分)
  10. 一步一步优化Windows XP(转)
  11. 特斯拉为什么要降价?
  12. 昇腾AI室外移动机器人原理与应用(二 初识室外移动机器人)
  13. 谁可以参与初创股权分配?
  14. 内部资料泄密,电信拨号软件系最大流氓软件
  15. Java 小项目——字符界面收银台(优化版)
  16. X86-64、X64、X86
  17. mysql查询数据库结构_mysql查询数据库下的表结构
  18. 游戏开发中,图片资源的精简
  19. 将必应输入法设置成纯英文的输入法,再也不必为切换中英文而烦恼了
  20. 计算机怎么游戏教学,谈计算机教学中的游戏教学法原稿(范文1)

热门文章

  1. 易恩电气自主研发生产的功率器件图示系统ENJ2005-C在深圳某电子公司上线运行。
  2. 字符串压缩与解压 题解
  3. java干洗店洗衣店管理系统_springboot_ssm_php
  4. [英语阅读]巨星迈克尔·杰克逊睡梦中辞世终年50岁
  5. 【Linux】Ubuntu下制作windows U盘启动盘
  6. EasyHook Creating a remote file monitor
  7. 软件工程-2.软件可行性研究
  8. Maven 3.6.3版本下载与安装
  9. word中如何从第N页开始设置页码并且前面的页不显示页码
  10. Kafka单机环境搭建及整合SpringBoot完成基本使用