ZZJC新生训练赛第二十场题解
链接:https://vjudge.net/contest/677776
密码:ZZJCACM
A-解题思路
(800)按照题意模拟,map存一下两两配对看有多少即可
A-代码实现
from collections import Counter
for _ in range(int(input())):
n = int(input())
a = list(map(int, input().split()))
c = Counter(a)
ans = 0
for i, j in c.items():
ans += j // 2
print(ans)
B-解题思路
(1300)赤石题,按照题意模拟每一次层就行,注意答案可能来自尾部和首部的拼接
B-代码实现
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int t;
std::cin >> t;
while (t--) {
int n, m;
std::cin >> n >> m;
std::vector<std::vector<char>> g(n, std::vector<char>(m));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
std::cin >> g[i][j];
}
}
int ans = 0;
for (int i = 0; i < std::min(n / 2, m / 2); i++) {
int x1 = i, y1 = i;
int x2 = i, y2 = m - i - 1;
int x3 = n - i - 1, y3 = m - i - 1;
int x4 = n - i - 1, y4 = i;
// std::cout << x1 << " " << y1 << " " << x2 << " " << y2 << " " << x3 << " " << y3 << " " << x4 << " " << y4 << "\n";
int siz = 0;
std::string s;
for (int x = x1, y = y1; y <= y2; y++) {
s += g[x][y];
siz++;
}
for (int x = x2 + 1, y = y2; x <= x3; x++) {
s += g[x][y];
siz++;
}
for (int x = x3, y = y3 - 1; y >= y4; y--) {
s += g[x][y];
siz++;
}
for (int x = x4 - 1, y = y4; x > x1; x--) {
s += g[x][y];
siz++;
}
s += s;
for (int j = 0; j < siz; j++) {
ans += s.substr(j, 4) == "1543";
}
}
std::cout << ans << "\n";
}
}
C-解题思路
(1000)人机构造题,乱搞一下就能发现至少要五个,然后根据奇偶放两侧就行
C-代码实现
for _ in range(int(input())):
n = int(input())
if n <= 4:
print(-1)
else:
l = []
r = []
mid = [3, 1, 5, 4, 2]
for i in range(6, n + 1):
if i % 2:
l.append(i)
else:
r.append(i)
print(*(l + mid + r))
D-解题思路
(1600)构造+交互,对于位置pos的询问显然满足如果pos和pos-1的答案相同则pos是0,否则pos是1。因此从最右侧一直往左边扫过去直到回答是0就能知道右侧的构成,此时需要回溯到上一次回答,要在左侧填充对应数量的0,剩余部分全填1即可
D-代码实现
#include <bits/stdc++.h>
int main() {
int t;
std::cin >> t;
while (t--) {
int n, f = 1, p = -1;
std::cin >> n;
if (n < 2) {
std::cout << "! IMPOSSIBLE" << std::endl;
continue;
}
std::string s;
for (int i = n; i >= 2; i--) {
std::cout << "? " << 1 << " " << i << std::endl;
std::cin >> f;
if (!f) {
break;
}
if (p == -1) {
p = f;
} else {
if (p == f) {
s = "0" + s;
} else {
p = f;
s = "1" + s;
}
}
}
s = "1" + s;
if (p == -1) {
std::cout << "! IMPOSSIBLE" << std::endl;
} else {
for (int i = 0; i < p; i++) {
s = "0" + s;
}
for (int i = s.size(); i < n; i++) {
s = "1" + s;
}
std::cout << "! " << s << std::endl;
}
}
}
E-解题思路
(800)用k的两个因数构造就行
E-代码实现
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int t;
std::cin >> t;
while (t--) {
int k;
std::cin >> k;
k -= 2;
std::vector<int> a(k + 2);
std::map<int, int> mp;
for (int i = 0; i < k + 2; i++) {
std::cin >> a[i];
mp[a[i]]++;
}
for (auto i : a) {
if (k % i == 0 && (mp.count(k / i) && i != k / i || k / i == i && mp[i] >= 2)) {
std::cout << i << " " << k / i << "\n";
break;
}
}
}
}
F-解题思路
(800)同品牌合并取最大的n个即可
F-代码实现
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(0);
std::cin.tie(0);
std::cout.tie(0);
int t;
std::cin >> t;
while (t--) {
int n, k;
std::cin >> n >> k;
std::map<int, i64> mp;
for (int i = 0; i < k; i++) {
int b, c;
std::cin >> b >> c;
mp[b] += c;
}
std::vector<i64> v;
for (auto [x, y] : mp) {
v.push_back(y);
}
std::sort(v.begin(), v.end(), std::greater<>());
i64 ans = 0;
for (int i = 0; i < n && i < (int)v.size(); i++) {
ans += v[i];
}
std::cout << ans << "\n";
}
}
G-解题思路
(1100)统计修改前后目标串的数量即可
G-代码实现
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int t;
std::cin >> t;
while (t--) {
std::string s;
std::cin >> s;
int q;
std::cin >> q;
int cnt = 0;
for (int i = 0; i + 3 < s.size(); i++) {
if (s.substr(i, 4) == "1100") {
cnt++;
}
}
while (q--) {
int i, v;
std::cin >> i >> v;
i--;
for (int j = std::max(0, i - 3); j <= i && j + 3 < s.size(); j++) {
if (s.substr(j, 4) == "1100") {
cnt--;
}
}
s[i] = v + '0';
for (int j = std::max(0, i - 3); j <= i && j + 3 < s.size(); j++) {
if (s.substr(j, 4) == "1100") {
cnt++;
}
}
if (cnt) {
std::cout << "YES\n";
} else {
std::cout << "NO\n";
}
}
}
return 0;
}
H-解题思路
(1600)枚举最后一场电影的位置减去对应的d(到i场就会有固定i*d个间隔),优先队列贪心地选择m个最大正数即可
H-代码实现
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int t;
std::cin >> t;
while (t--) {
i64 n, m, d;
std::cin >> n >> m >> d;
i64 ans = 0, sum = 0;
std::priority_queue<i64, std::vector<i64>, std::greater<>> pq;
for (int i = 1; i <= n; i++) {
int x;
std::cin >> x;
if (x > 0) {
pq.push(x);
sum += x;
}
while (pq.size() > m) {
sum -= pq.top();
pq.pop();
}
ans = std::max(ans, sum - i * d);
}
std::cout << ans << "\n";
}
}
I-解题思路
(1600)一种简单的思路是让最小生成树就是最短路,让权重和为第一个不小于m的质数,可用一堆1和一个剩余的数字来构成这个质数,暴力枚举没用过的边全都设为无穷大让他们不能选即可
I-代码实现
#include <bits/stdc++.h>
const int N = 1e6 + 10;
const int INF = 1e9;
std::vector<int> primes;
bool f[N];
void euler(int n) {
for (int i = 2; i <= n; i++) {
if (!f[i]) {
primes.push_back(i);
}
for (int prime : primes) {
if (i * prime > n) {
break;
}
f[i * prime] = true;
if (i % prime == 0) {
break;
}
}
}
}
int main() {
std::ios::sync_with_stdio(0);
std::cin.tie(0);
std::cout.tie(0);
euler(N);
int n, m;
std::cin >> n >> m;
int ans = *std::lower_bound(primes.begin(), primes.end(), m);
std::cout << ans << " " << ans << "\n";
std::set<std::array<int, 2>> st;
for (int i = 1; i <= n - 2; i++) {
std::cout << i << " " << i + 1 << " " << 1 << "\n";
st.insert({i, i + 1});
}
std::cout << n - 1 << " " << n << " " << ans - n + 2 << "\n";
st.insert({n - 1, n});
m -= n - 1;
if (m == 0) {
return 0;
}
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
if (!st.count({i, j})) {
std::cout << i << " " << j << " " << INF << "\n";
st.insert({i, j});
m--;
if (m == 0) {
return 0;
}
}
}
}
}

浙公网安备 33010602011771号