2025CSP-S模拟赛24 比赛总结
2025CSP-S模拟赛24
| T1 | T2 | T3 | T4 |
|---|---|---|---|
| 20 WA | 0 WA | 20 TLE | 0TLE |
排名:14/22;总分:40
T1 傻逼构造,构造炸了。T2 不会,T3 暴力,T4 暴力挂了。
T1 构造
傻逼构造。
#include <bits/stdc++.h>
#define il inline
using namespace std;
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;
}
const int N = 2300, M = 50;
int n;
int a[M][M];
int main() {
n = read();
int cnt = 0, h = 40, w = 40;
for (int i = 1; i <= h; i++)
for (int j = 1; j <= w; j++) a[i][j] = 1;
int k = 0;
for (k = 0; k < 9 && cnt + 232 <= n; k++) {
int i = k * 4;
for (int j = 1; j <= w; j++) a[i + 1][j] = 1;
for (int j = 1; j <= w; j++) a[i + 2][j] = 2;
for (int j = 1; j <= w; j++) a[i + 3][j] = 3;
for (int j = 1; j <= w; j++) a[i + 4][j] = 2;
cnt += 232;
}
int l1 = k * 4 + 1, l2 = k * 4 + 2, l3 = k * 4 + 3;
for (int i = 1; i <= w; i++) {
a[l1][i] = 1;
}
if (n - cnt <= 3) {
for (int i = 1; i <= w && cnt < n; i += 4) {
a[h][i] = 1, a[h][i + 1] = 2, a[h][i + 2] = 3;
cnt++;
}
for (int i = 1; i <= w && cnt < n; i += 4) {
a[h][i + 3] = 2;
cnt++;
}
} else {
a[l2][1] = 2, a[l3][1] = 3;
a[l2][2] = 2, a[l3][2] = 3;
cnt += 3;
int j;
for (j = 3; j < w && cnt + 3 <= n; j++) {
a[l2][j] = 2, a[l3][j] = 3;
cnt += 3;
}
if (n - cnt >= 2 && j == w) {
a[l2][j] = 2, a[l3][j] = 3;
cnt += 2;
}
if (n - cnt >= 3 && j < w) {
a[l2][j] = 2, a[l3][j] = 3;
cnt += 3;
}
}
if (n - cnt > 13 && k < 9) {
l1 += 3, l2 += 3, l3 += 3;
for (int i = 1; i <= w; i++) {
a[l1][i] = 1;
}
a[l2][1] = 2, a[l3][1] = 3;
a[l2][2] = 2, a[l3][2] = 3;
cnt += 3;
int j;
for (j = 3; j < w && cnt + 3 <= n; j++) {
a[l2][j] = 2, a[l3][j] = 3;
cnt += 3;
}
if (n - cnt >= 2 && j == w) {
a[l2][j] = 2, a[l3][j] = 3;
cnt += 2;
}
if (n - cnt >= 3 && j < w) {
a[l2][j] = 2, a[l3][j] = 3;
cnt += 3;
}
}
for (int i = 1; i < w && cnt < n; i += 3) {
for (int i = 1; i <= w && cnt < n; i += 4) {
a[h][i] = 1, a[h][i + 1] = 2, a[h][i + 2] = 3;
cnt++;
}
for (int i = 1; i <= w && cnt < n; i += 4) {
a[h][i + 3] = 2;
cnt++;
}
}
printf("%d %d\n", h, w);
for (int i = 1; i <= h; i++) {
for (int j = 1; j <= w; j++) {
if (a[i][j] == 1) printf("r");
if (a[i][j] == 2) printf("y");
if (a[i][j] == 3) printf("x");
}
printf("\n");
}
return 0;
}
T2 游戏
傻逼二极管题(全场不是 100 就是 0)。
二分答案 \(mid\),我们只关注学生能否使得被抓人数 \(\le mid\)。
那么,人数 \(\le mid\) 的实验室就无关紧要了,我们只考虑人数大于 \(mid\) 的实验室。设同学有 \(p_i\) 的概率进入这个实验室,那么老师如果进入这个实验室抓到人的期望就是 \((1-p_i)\times a_i\)。所以我们要求对于任意这样的 \(a_i\),都有 \((1-p_i)\times a_i\le mid\),据此求出 \(p_i\) 的下界,判断全加起来到不到 \(1\) 即可。
没了。
#include <bits/stdc++.h>
#define il inline
using namespace std;
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;
}
const double eps = 1e-12;
const int N = 30 + 10;
int n, a[N];
il bool check(double mid) {
double p = 0;
for (int i = 1; i <= n; i++) {
if (a[i] > mid) {
p += 1.0 - mid * 1.0 / a[i];
}
}
return p >= 1;
}
int main() {
n = read();
int mx = 0;
for (int i = 1; i <= n; i++) {
a[i] = read();
mx = max(mx, a[i]);
}
double L = 0, R = mx, ans = 0;
while (L + eps < R) {
double mid = (L + R) / 2.0;
if (check(mid)) {
ans = mid;
L = mid;
} else {
R = mid;
}
}
printf("%.12lf\n", ans);
return 0;
}
T3 数数
T4 滈葕
出题人也是人才。
据 UKE_Automation 所说(本题英文名为 dopetobly):
这个题目标题和英文令人捉摸不透,考虑进行搜索,然后发现汉字标题和英文都不是一个有意义的词,所以需要进行一些脑洞。考虑谐音,发现这两个字都是多音字,也很难看出其真正含义。真正的突破口在于这个不存在的英文单词,注意到将字母重排后可以得到单词
bloodtype,即血型,并且正好可以和前面的汉字对应,所以我们确定了题目标题想表达的含义是血型。
这是题解给的一段资料:
ABO 血型系统是血型系统的一种,把血液分为 A,B,AB,O 四种血型。血液由红细胞和血清等组成,红细胞表面 有凝集原,血清内有凝集素。根据红细胞表面有无凝集原 A 和 B 来划分血液类型。红细胞上只有凝集原 A 的 为 A 型血,其血清中有抗 B 凝集素;红细胞上只有凝集原 B 的为 B 型血,其血清中有抗 A 凝集素;红细胞上 两种凝集原都有的为 AB 型血,其血清中无凝集素;红细胞上两种凝集原皆无者为 O 型,其血清中两种凝集素 皆有。有凝集原 A 的红细胞可被抗 A 凝集素凝集;有凝集原 B 的红细胞可被抗 B 凝集素凝集。配血试验是两 个人分别提供红细胞和血清并将其混合,观察是否有凝集反应。
然后,我们发现,A,B,C,D 的点权可以分别代表 A,B,AB,O 型血,然后一条边代表一次配血试验,边权表示是否发生凝集。
考虑将一种血型拆成“X 凝集原 + 抗 Y 凝集素”的形式,由于同种凝集原和同种凝集素不能同时出现,那么我们就把这道题转化成了一个 2-SAT 问题(小编觉得这种做法非常巧妙,于是去学习了 2-SAT)。对每一个点设置 \(a_i,b_i\),分别表示是否含有 A/B 凝集原。对每一条边根据是否发生凝集列出与或式,然后跑 2-SAT 就行了。具体的:
显然 A 凝集原和抗 A 凝集素相遇的条件是 \(a_x \wedge \neg a_y\),B 种同理。那么,每次配血试验写下来就是:\(w=(a \wedge \neg a_y) \vee (b_x \wedge \neg b_y)\)。
若 \(w=0\),则有 \(\neg\left(a_{x} \wedge \neg a_{y}\right) \wedge \neg\left(b_{x} \wedge \neg b_{y}\right)=\left(\neg a_{x} \vee a_{y}\right) \wedge\left(\neg b_{x} \vee b_{y}\right)\)。
若 \(w=1\),则有 $\left(a_{x} \wedge \neg a_{y}\right) \vee\left(b_{x} \wedge \neg b_{y}\right)=\left(a_{x} \vee b_{x}\right) \wedge\left(a_{x} \vee \neg b_{y}\right) \wedge\left(\neg a_{y} \vee b_{x}\right) \wedge\left(\neg a_{y} \vee \neg b_{y}\right) $。
#include <bits/stdc++.h>
#define il inline
using namespace std;
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;
}
const int N = 2e6 + 10;
int n, m;
vector<int> G[N];
il int P(int x, int a) {return a ? x + n : x;}
il int V(int x, int a) {return a ? x : x + 2 * n;}
il void add(int x, int a, int y, int b) {
G[V(x, a ^ 1)].push_back(V(y, b));
G[V(y, b ^ 1)].push_back(V(x, a));
}
int dfn[N], low[N], tot, inst[N], st[N], head, scc[N], cnt;
il void tarjan(int x) {
dfn[x] = low[x] = ++tot;
st[++head] = x;
inst[x] = 1;
for (int y : G[x]) {
if (!dfn[y]) {
tarjan(y);
low[x] = min(low[x], low[y]);
} else if (inst[y]) {
low[x] = min(low[x], dfn[y]);
}
}
if (dfn[x] == low[x]) {
cnt++;
while (true) {
int y = st[head--];
inst[y] = 0;
scc[y] = cnt;
if (x == y) break;
}
}
}
int main() {
n = read(), m = read();
for (int i = 1; i <= m; i++) {
int x = read(), y = read(), w = read();
if (w == 0) {
add(P(x, 0), 0, P(y, 0), 1);
add(P(x, 1), 0, P(y, 1), 1);
} else {
add(P(x, 0), 1, P(x, 1), 1);
add(P(x, 0), 1, P(y, 1), 0);
add(P(y, 0), 0, P(x, 1), 1);
add(P(y, 0), 0, P(y, 1), 0);
}
}
for (int i = 1; i <= 4 * n; i++) {
if (!dfn[i]) tarjan(i);
}
for (int i = 1; i <= n * 2; i++) {
if (scc[i] == scc[i + n * 2]) {
printf("NO\n");
return 0;
}
}
printf("YES\n");
for (int i = 1; i <= n; i++) {
int aa = (scc[i + 2 * n] < scc[i]);
int bb = (scc[i + n + 2 * n] < scc[i + n]);
if (aa && !bb) printf("B");
if (!aa && bb) printf("A");
if (aa && bb) printf("D");
if (!aa && !bb) printf("C");
}
return 0;
}

浙公网安备 33010602011771号