[BZOJ2253][2010 Beijing wc]纸箱堆叠(CDQ分治优化DP)
2018-01-06 19:43
344 查看
考虑一个朴素的DP方案:
先求出所有纸箱的最短边(以下第i个纸箱的最短边记为xi),次短边(以下第i个纸箱次短边记为yi)和最长边(以下记为zi),然后按照xi从小到大排序。
这样,就变成了一个求最长严格上升子序列的问题,即f[i]为到了第i个纸箱,且必须选第i个纸箱的最优解:
f[i]=1+maxxj<xi,yj<yi,zj<zif[j]
但这样显然是O(n2)的,TLE。考虑优化。
考虑一般的LIS优化:一般的LIS,可以将序列离散化之后,用树状数组进行优化。但这里有y和z两个关键字,不能简单地用树状数组优化。
还是先离散化序列,设有一个平面,把每一个决策都看作一个点(yi,zi),权值为f[i]。那么在不考虑xi相等的情况下,
求maxxj<xi,yj<yi,zj<zif[j]就是求点(yi−1,zi−1)的左下角的点的最大权值。决策结束之后,还需要把点(yi,zi)插入平面。因此,考虑CDQ分治,就能得到O(nlog2n)的算法。但这与普通的CDQ分治有两点区别:
1、将[l,r]操作区间分成两个小的操作区间时,有时不能取中点作为分界点。假设分界点为mid,分成了[l,mid]和[mid+1,r]两个小操作区间,那么绝对不能有xmid=xmid+1,否则有可能使f[i]从满足xj=xi的j转移过来。
2、必须要先递归左子区间,处理完左子区间对右子区间的贡献后再递归右子区间。
代码:
先求出所有纸箱的最短边(以下第i个纸箱的最短边记为xi),次短边(以下第i个纸箱次短边记为yi)和最长边(以下记为zi),然后按照xi从小到大排序。
这样,就变成了一个求最长严格上升子序列的问题,即f[i]为到了第i个纸箱,且必须选第i个纸箱的最优解:
f[i]=1+maxxj<xi,yj<yi,zj<zif[j]
但这样显然是O(n2)的,TLE。考虑优化。
考虑一般的LIS优化:一般的LIS,可以将序列离散化之后,用树状数组进行优化。但这里有y和z两个关键字,不能简单地用树状数组优化。
还是先离散化序列,设有一个平面,把每一个决策都看作一个点(yi,zi),权值为f[i]。那么在不考虑xi相等的情况下,
求maxxj<xi,yj<yi,zj<zif[j]就是求点(yi−1,zi−1)的左下角的点的最大权值。决策结束之后,还需要把点(yi,zi)插入平面。因此,考虑CDQ分治,就能得到O(nlog2n)的算法。但这与普通的CDQ分治有两点区别:
1、将[l,r]操作区间分成两个小的操作区间时,有时不能取中点作为分界点。假设分界点为mid,分成了[l,mid]和[mid+1,r]两个小操作区间,那么绝对不能有xmid=xmid+1,否则有可能使f[i]从满足xj=xi的j转移过来。
2、必须要先递归左子区间,处理完左子区间对右子区间的贡献后再递归右子区间。
代码:
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; inline int read() { int res = 0; bool bo = 0; char c; while (((c = getchar()) < '0' || c > '9') && c != '-'); if (c == '-') bo = 1; else res = c - 48; while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + (c - 48); return bo ? ~res + 1 : res; } const int N = 2e5 + 5; int A, ZZQ, n, orz [4], tot, T , tm , to ; struct cyx { int x, y, z, ans; cyx() {} cyx(int _x, int _y, int _z) : x(_x), y(_y), z(_z) {} friend inline bool operator < (cyx a, cyx b) { if (a.y != b.y) return a.y < b.y; return a.z < b.z; } } a , c ; inline bool comp(const cyx &a, const cyx &b) { if (a.x != b.x) return a.x < b.x; if (a.y != b.y) return a.y < b.y; return a.z < b.z; } inline bool comp1(const cyx &a, const cyx &b) { return a.x < b.x; } inline bool comp2(const cyx &a, const cyx &b) { return a.y < b.y; } inline bool comp3(const cyx &a, const cyx &b) { return a.z < b.z; } void orzdalao(int x) { for (; x <= n * 3; x += x & -x) if (T[x] != 0) T[x] = 0; else return; } void change(int x, int v) { for (; x <= n * 3; x += x & -x) T[x] = max(T[x], v); } int ask(int x) { int res = 0; for (; x; x -= x & -x) res = max(res, T[x]); return res; } void czk_is_so_weak(int l, int r) { if (l == r) return; int i, mid = l + r >> 1, p1 = mid, p2 = mid + 1; if (a[p1].x == a[p2].x) { while (p1 >= l && a[p1].x == a[mid].x) p1--; while (p2 <= r && a[p2].x == a[mid + 1].x) p2++; p2--; if (p1 == l - 1 && p2 == r) return; if (p1 == l - 1) mid = p2; else if (p2 == r) mid = p1; else { int x = abs((r - p1) - (p1 - l + 1)), y = abs((r - p2) - (p2 - l + 1)); mid = x < y ? p1 : p2; } } czk_is_so_weak(l, mid); sort(a + l, a + mid + 1); sort(a + mid + 1, a + r + 1); p1 = l; p2 = mid + 1; for (i = l; i <= r; i++) if (p2 > r || (p1 <= mid && a[p1].y < a[p2].y)) change(a[p1].z, a[p1].ans), p1++; else a[p2].ans = max(a[p2].ans, ask(a[p2].z - 1) + 1), p2++; for (i = l; i <= mid; i++) orzdalao(a[i].z); sort(a + mid + 1, a + r + 1, comp); czk_is_so_weak(mid + 1, r); } int main() { freopen("box.in", "r", stdin); freopen("box.out", "w", stdout); int i, j, nxt, now = 1; A = read(); ZZQ = read(); n = read(); for (i = 1; i <= n; i++) for (j = 1; j <= 3; j++) orz[i][j] = (now = 1ll * now * A % ZZQ); for (i = 1; i <= n; i++) sort(orz[i] + 1, orz[i] + 4); for (i = 1; i <= n; i++) c[i] = cyx(orz[i][1], orz[i][2], orz[i][3]); sort(c + 1, c + n + 1, comp1); tot = 0; for (i = 1; i <= n; i++) { if (i == 1 || c[i].x != c[i - 1].x) tot++; tm[i] = tot; } for (i = 1; i <= n; i++) c[i].x = tm[i]; sort(c + 1, c + n + 1, comp2); tot = 0; for (i = 1; i <= n; i++) { if (i == 1 || c[i].y != c[i - 1].y) tot++; tm[i] = tot; } for (i = 1; i <= n; i++) c[i].y = tm[i]; sort(c + 1, c + n + 1, comp3); tot = 0; for (i = 1; i <= n; i++) { if (i == 1 || c[i].z != c[i - 1].z) tot++; tm[i] = tot; } for (i = 1; i <= n; i++) c[i].z = tm[i]; for (i = 1; i <= n; i++) a[i] = c[i], a[i].ans = 1; sort(a + 1, a + n + 1, comp); czk_is_so_weak(1, n); int ans = 0; for (i = 1; i <= n; i++) ans = max(ans, a[i].ans); cout << ans << endl; return 0; }
相关文章推荐
- [BZOJ 2253][2010 Beijing wc]纸箱堆叠:CDQ分治|DP
- 【BZOJ2253】[2010 Beijing wc]纸箱堆叠 cdq分治
- BZOJ 2253 纸箱堆叠(CDQ分治)
- BZOJ2253: [2010 Beijing wc]纸箱堆叠
- 【BZOJ】2253: [2010 Beijing wc]纸箱堆叠
- bzoj2253 [2010 Beijing wc]纸箱堆叠(CDQ+dp)
- BZOJ2253 2010 Beijing wc 纸箱堆叠 CDQ分治
- bzoj2253 [2010 Beijing wc]纸箱堆叠(cdq分治+树状数组)
- 【BZOJ2253】纸箱堆叠 [CDQ分治]
- bzoj2253: [2010 Beijing wc]纸箱堆叠
- [BZOJ2253][2010 Beijing wc]纸箱堆叠(dp+bit+cdq分治)
- BZOJ_2253_[2010 Beijing wc]纸箱堆叠 _CDQ分治+树状数组
- bzoj 2253: [2010 Beijing wc]纸箱堆叠 (CDQ分治+DP)
- [BZOJ 3963][WF2011]MachineWorks:CDQ分治|DP斜率优化
- BZOJ 1492: [NOI2007]货币兑换Cash [CDQ分治 斜率优化DP]
- BZOJ1492 货币兑换 CDQ分治优化DP
- BZOJ 1492 斜率优化dp && cdq分治
- [BZOJ3963][WF2011][CDQ分治][斜率优化][DP]MachineWorks
- [BZOJ 1492][NOI2007]货币兑换Cash:CDQ分治|DP斜率优化
- [BZOJ1492][NOI2007][CDQ分治][斜率优化][DP]货币兑换Cash