2025CSP-S模拟赛51 比赛总结
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 inline
using 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 inline
using 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;
}