考虑一个朴素的DP方案:
先求出所有纸箱的最短边(以下第
这样,就变成了一个求最长严格上升子序列的问题,即
但这样显然是
考虑一般的LIS优化:一般的LIS,可以将序列离散化之后,用树状数组进行优化。但这里有
还是先离散化序列,设有一个平面,把每一个决策都看作一个点
求
1、将
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[N][4], tot, T[N], tm[N], to[N];
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[N], c[N];
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;
}