2025CSP-S模拟赛51
T1 | T2 | T3 | T4 |
---|---|---|---|
30 TLE | 18 WA | 54 TLE | - |
总分:102;排名:19/24。
打得很唐氏。T1 挂了 70 分,T2 本可以做出来的,没调出来。
T1 算术
考虑对原式进行变形(省略过程):
\[\left\{\begin{align*}
& a_i \le \frac{a_j}{a_j-1}\land a_j>1 \\
& a_j=1\\
& a_i \le \frac{a_j}{1-a_j} \land a_j<1
\end{align*}\right.
\]
然后不难发现这个 \(\frac{a_j}{a_j-1}\) 的值就是 \(1\)(差不多就是)。然后 \(O(n)\) 去跑就行了。考试时比较唐氏,只推导到了上面的式子,写了线段树,然后被卡常了。经过卡常是可以通过的。
#include <bits/stdc++.h>
#define il inlineusing namespace std;const int bufsz = 1 << 20;
char ibuf[bufsz], *p1 = ibuf, *p2 = ibuf;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, bufsz, stdin), p1 == p2) ? EOF : *p1++)
il int read() {int x = 0; char ch = getchar(); bool t = 0;while (ch < '0' || ch > '9') {t ^= ch == '-'; ch = getchar();}while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}return t ? -x : x;
}
bool Beg;
const int maxm = 1e9;
const int N = 1e6 + 10;
int n, a[N];
int root;
int ll[N * 20], rr[N * 20];
long long s[N * 20];
int tot;
#define lc ll[p]
#define rc rr[p]
#define mid ((l + r) >> 1)
il void update(int &p, int l, int r, int x) {if (!p) p = ++tot;s[p]++;if (l == r) return;if (x <= mid) update(lc, l, mid, x);else update(rc, mid + 1, r, x);
}
int query(int p, int l, int r, int x, int y) {if (!p) return 0;if (l == x && y == r) return s[p];if (y <= mid) return query(lc, l, mid, x, y);else if (x > mid) return query(rc, mid + 1, r, x, y);else return query(lc, l, mid, x, mid) + query(rc, mid + 1, r, mid + 1, y);
}
bool End;
il void Usd() {cerr << "\nUsed: " << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n";}
signed main() {n = read();for (int i = 1; i <= n; i++) {a[i] = read();}long long ans = 0;for (int i = 1; i <= n; i++) {if (a[i] - 1 == 0) {ans += i - 1;} else if (a[i] - 1 > 0) {ans += query(root, -maxm, maxm, -maxm, (int)ceil(1.0 * a[i] / (a[i] - 1)) - 1);} else {ans += query(root, -maxm, maxm, (int)floor(1.0 * a[i] / (a[i] - 1)) + 1, maxm);}update(root, -maxm, maxm, a[i]);}printf("%lld\n", ans);Usd();return 0;
}
T2 刷墙
考场上基本写出来了。
区间 dp。\(f_{i,j}\) 表示 \([i,j]\) 米,只用完全包含在这个区间内的刷子,的最大颜色。转移很简单,无非是:
- 直接继承子区间。
- 从一个子区间向外扩展一种颜色。
- 两个子区间中间通过一种颜色链接。
#include <bits/stdc++.h>
#define il inlineusing namespace std;const int bufsz = 1 << 20;
char ibuf[bufsz], *p1 = ibuf, *p2 = ibuf;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, bufsz, stdin), p1 == p2) ? EOF : *p1++)
il int read() {int x = 0; char ch = getchar(); bool t = 0;while (ch < '0' || ch > '9') {t ^= ch == '-'; ch = getchar();}while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}return t ? -x : x;
}
bool Beg;
const int INF = 0x3f3f3f3f;
const int N = 600 + 10;
int n;
struct node {int l, r;
} a[N];
int ll[N], tot, L;
int f[N][N];
struct ST {int mn[N][15], Log2[N];il void init() {for (int i = 2; i <= L; i++) Log2[i] = Log2[i / 2] + 1;for (int i = 1; i <= L; i++) mn[i][0] = INF;}il void init1() {for (int j = 1; j <= Log2[L]; j++) {for (int i = 1; i + (1 << j) - 1 <= L; i++) {mn[i][j] = min(mn[i][j - 1], mn[i + (1 << (j - 1))][j - 1]);}}}il int query(int l, int r) {int s = Log2[r - l + 1];return min(mn[l][s], mn[r - (1 << s) + 1][s]);}
} st[N];
il bool cmp(int x, int y) {return a[x].l != a[y].l ? a[x].l < a[y].l : a[x].r < a[y].r;
}
bool End;
il void Usd() {cerr << "\nUsed: " << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n";}
int main() {n = read();for (int i = 1; i <= n; i++) {int l = read() + 1, r = read();a[i] = {l, r};ll[++tot] = l;ll[++tot] = r;}sort(ll + 1, ll + 1 + tot);L = unique(ll + 1, ll + 1 + tot) - ll - 1;int mn = 2;for (int i = 1; i <= n; i++) {a[i].l = lower_bound(ll + 1, ll + 1 + L, a[i].l) - ll;a[i].r = lower_bound(ll + 1, ll + 1 + L, a[i].r) - ll;f[a[i].l][a[i].r] = 1;mn = min(mn, a[i].r - a[i].l + 1);}for (int i = 1; i <= L; i++) {st[i].init();for (int j = 1; j <= n; j++) {if (a[j].l <= i && i < a[j].r) {st[i].mn[a[j].l][0] = min(st[i].mn[a[j].l][0], a[j].r);}}st[i].init1();}for (int len = mn; len <= L; len++) {for (int i = 1; i + len - 1 <= L; i++) {int j = i + len - 1;f[i][j] = max(f[i + 1][j], f[i][j - 1]);for (int k = i; k < j; k++) {f[i][j] = max(f[i][j], f[i][k] + f[k + 1][j]);}for (int t = 1; t <= n; t++) {if (a[t].l < i || a[t].r > j) continue;if (a[t].l == i) f[i][j] = max(f[i][j], f[i + 1][j] + 1);if (a[t].r == j) f[i][j] = max(f[i][j], f[i][j - 1] + 1);}for (int k = i; k < j; k++) {if (ll[k] + 1 < ll[k + 1] && st[k].query(i, j) <= j) {f[i][j] = max(f[i][j], f[i][k] + f[k + 1][j] + 1);} if (k > i && (st[k - 1].query(i, j) <= j || st[k].query(i, j) <= j)) {f[i][j] = max(f[i][j], f[i][k - 1] + f[k + 1][j] + 1);}}}}printf("%d\n", f[1][L]);Usd();return 0;
}