2025 CCH非专业级软件能力认证提高级第十二轮总结
呜呜呜set常数怎么那么大,
今天还捆绑呜呜呜,大挂分。
预期:100 + 100 + 0 + 40
实际:40 + 100 + 0 + 40
T1
原题
今天有点弱智,前30min都没想到T1。
可以发现每次修改只影响一列一行,所以我们用set记下每一行和每一列,这样就可以查最大值,还能修改。再看看这一行和这一列中的最大值是否合法,计算答案。
直接开始写,写到一半又想拉屎,拉完回来45min了,写完刚好50min。
#include <bits/stdc++.h>
using namespace std;
const int kMaxN = 2e5 + 5;
int n, m, q, ans;
vector<int> a[kMaxN];
set<int> r[kMaxN], c[kMaxN], s;
unordered_map<int, pair<int, int>> mp;
bool check(int x) {
return (*r[mp[x].first].rbegin()) == (*c[mp[x].second].rbegin());
}
int main() {
cin >> n >> m >> q;
for (int i = 1; i <= n; i++) {
a[i].push_back(0);
for (int j = 1, x; j <= m; j++) {
cin >> x;
mp[x] = {i, j};
r[i].insert(x);
c[j].insert(x);
a[i].push_back(x);
}
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
ans += ((*r[i].rbegin()) == (*c[j].rbegin()));
for (int z, y, t; q; q--) {
cin >> z >> y >> t;
ans -= check((*r[z].rbegin())) + check((*c[y].rbegin())) - ((*r[z].rbegin()) == (*c[y].rbegin()));
r[z].erase(a[z][y]);
c[y].erase(a[z][y]);
a[z][y] = t;
mp[t] = {z, y};
r[z].insert(t);
c[y].insert(t);
ans += check((*r[z].rbegin())) + check((*c[y].rbegin())) - ((*r[z].rbegin()) == (*c[y].rbegin()));
cout << ans << '\n';
}
return 0;
}
这里就可以引出我的挂分的根本原因了。注意题目中写到只会修改为更大的值,所以只需要记录一个最大值,修改就直接与修改后的值取最大值。
赛后补题:
#include <bits/stdc++.h>
using namespace std;
const int kMaxN = 2e5 + 5;
int n, m, q, ans, r[kMaxN], c[kMaxN];
vector<int> a[kMaxN];
unordered_map<int, pair<int, int>> mp;
bool check(int x) {
return r[mp[x].first] == c[mp[x].second];
}
int main() {
cin >> n >> m >> q;
for (int i = 1; i <= n; i++) {
a[i].push_back(0);
for (int j = 1, x; j <= m; j++) {
cin >> x;
mp[x] = {i, j};
r[i] = max(r[i], x);
c[j] = max(c[j], x);
a[i].push_back(x);
}
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
ans += (r[i] == c[j]);
for (int z, y, t; q; q--) {
cin >> z >> y >> t;
ans -= check(r[z]) + check(c[y]) - (r[z] == c[y]);
r[z] = max(r[z], t);
c[y] = max(c[y], t);
a[z][y] = t;
mp[t] = {z, y};
ans += check(r[z]) + check(c[y]) - (r[z] == c[y]);
cout << ans << '\n';
}
return 0;
}
捆绑测试我爱你,set我爱你,DFbd我爱你。
T2
T2和T3混着看的,然后就很爆炸,想了很久很久,直到2h40min时才会T2呜呜呜。
T2 T3
显然,只有细胞
接下来我们需要判断病毒是否可行。
只要有一个细胞可以使该病毒寄生并不会被消灭,该病毒就可行。
所以我们只需要枚举细胞,再枚举病毒寄生于该细胞是否可行。
而可行的条件即为,所有该细胞中易感染度高于该病毒的易感染度的病毒存活在初始细胞中,可以被易感染度低于该病毒的病毒直接消灭。
所以,我们将可以直接消灭存活于细胞
枚举病毒时,按照易感染度从低往高枚举,先判断是否可行,再将该点和与该点直接相邻的点打上标记,并统计标记个数。
若标记个数减去当前病毒的标记
#include <bits/stdc++.h>
using namespace std;
int n, a[505][505], p, cnt, f[505];
vector<int> ans, e[505];
void fill(int x) {
f[x] = 1;
cnt++;
for (int i : e[x])
if (!f[i]) {
f[i] = 1;
cnt++;
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
int flag = 0;
for (int j = 1; j <= n; j++) {
cin >> a[i][j];
if (a[i][j] == i)
flag = 1;
if (!flag)
e[a[i][j]].push_back(i);
}
if (a[i][1] == i) {
cnt++;
ans.push_back(i);
}
}
cin >> p;
if (p == 1) {
cout << cnt << '\n';
for (int i : ans)
cout << i << ' ';
} else {
set<int> s;
for (int i = 1; i <= n; i++) {
cnt = 0;
memset(f, 0, sizeof(f));
for (int j = n; j; j--) {
if (cnt - f[a[i][j]] >= n - 1)
s.insert(a[i][j]);
if (!f[a[i][j]])
fill(a[i][j]);
}
}
cout << s.size() << '\n';
for (int i : s)
cout << i << ' ';
}
return 0;
}
T3
别看了,没时间写了呜呜呜。
T4
原题