2024牛客暑期多校8
# A - Haitang and Game
# Question
给定一个集合,dXqwq 和海棠轮流进行以下运算,dXqwq 先进行:
找出一对,使得和。
将插入。
无法下棋的棋手输掉对局。当两位棋手都以最佳方式下棋时,您需要输出赢家。
# Solution
其实这里是一个假博弈, 是最终结果是固定的,关键在于 是奇数还是偶数,考虑求 的大小
由于 不大,假设 的最大值为 ,从 到 枚举每个数
设 的倍数集合 如果 中所有数的 为 ,那么说明 存在在 中
# Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
int N; cin >> N;
vector<int> A(N);
for (int i = 0; i < N; i++) cin >> A[i];
int M = *max_element(A.begin(), A.end());
vector<int> cnt(M + 1, 0);
for (auto &a : A) cnt[a] = 1;
int num = 0;
for (int i = M; i >= 1; i--) {
int g = 0;
for (int j = i; j <= M; j += i) {
if (cnt[j]) g = __gcd(g, j);
}
if (g == i) {
if (cnt[i] == 0) {
num += 1;
cnt[i] = 1;
}
}
}
if (num & 1)
cout << "dXqwq" << '\n';
else
cout << "Haitang" << '\n';
}
int main() {
ios::sync_with_stdio(false);
int T; cin >> T;
while (T--) solve();
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# E - Haitang and Math
# Question
海棠将正整数的定义为中的数字之和。
例如,,。
给定一个正整数 ,数一数有多少个正整数 使得 。
# Solution
考到了一个我以前不会的东西,然后就去学了一下
考虑到 其实很小,最大为 ,那么枚举
我们需要找到 的每个因数 ,然后去查看是否满足这个式子
容易想到把 质因数分解,然后用 dfs 枚举每个质因数出现的次数,从而达到高效枚举因数
思考如何质因数分解,朴素来说,质因数分解就是
for (p : prime)
int cnt = 0
while (x % p == 0)
x /= p, cnt += 1
2
3
4
这样的时间复杂度是 的
我们这里的 实在区间 的范围内的,这里就需要一种区间筛的东西
考虑区间内 那么,我们很容易能得出下一个被 整除的数,即 ,直到超出区间右边界
那么,如何才能找到第一个 的 ,假设区间为 ,则
这样就能把 中的每个数进行质因数分解了
关于这个的时间复杂度,我不知道怎么计算,题解给出是
# Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn = 1e6 + 5;
constexpr int M = 108;
vector<int> prime;
int s(int x) {
int ret = 0;
while (x) {
ret += x % 10;
x /= 10;
}
return ret;
}
vector<int> get_prime() {
vector<int> prime;
vector<int> vis(maxn, 0);
for (int i = 2; i < maxn; i++) {
if (vis[i] == 0) {
prime.push_back(i);
for (int j = i + i; j < maxn; j += i)
vis[j] = 1;
}
}
return prime;
}
void solve() {
int n; cin >> n;
const int L = max(n - M, 1ll), R = n, len = R - L + 1;
vector<int> a(len);
vector<vector<pair<int, int>>> p(len, vector<pair<int, int>>(0));
for (int i = L; i <= R; i++) a[i - L] = i;
for (auto v : prime) {
int pos = (L + v - 1) / v * v - L;
if (pos >= len) continue;
for (int i = pos; i < len; i += v) {
int cnt = 0;
while (a[i] % v == 0) {
a[i] /= v; cnt += 1;
}
if (cnt) p[i].push_back({v, cnt});
}
}
for (int i = 0; i < len; i++) {
if (a[i] > 1) p[i].push_back({a[i], 1});
}
set<int> ans;
auto dfs = [&] (auto &&dfs, int pos, int now, vector<pair<int, int>> &p) -> void {
auto [pr, cnt] = p[pos];
if (pos == (int)p.size()) {
int Sm = s(now);
if (n % now == Sm) ans.insert(now);
return;
}
for (int i = 0; i <= cnt; i++) {
dfs(dfs, pos + 1, now, p);
now *= pr;
}
};
for (int i = 0; i < len; i++) {
if (p[i].empty()) continue;
dfs(dfs, 0, 1, p[i]);
}
cout << ans.size() << '\n';
}
signed main() {
ios::sync_with_stdio(false);
int T; cin >> T;
prime = get_prime();
while (T--) solve();
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# J - Haitang and Triangle
# Question
给定两个整数 ,构造一个长度为 的排列组合,它满足以下条件。
- 恰好有 个长度为 的子区间,使得这些子区间中的数字构成一个(非退化的)三角形。
# Solution
雨巨说:构造题就要多手玩,然后找到一些规律和性质,其实没有想象的那么难
我们先考虑极端情况,显然 肯定是无解,因为 不能和其他的构成三角形
我们能构造出一种 的方法:
然后考虑 的情况,我们三个为一组,用大的数作为每组中的右端点,然后用两个小的数来尽量平衡的填在大的数之中,假设 ,那么一种可行的方法就是
通过观察可以发现, 的位置递增, 的位置递减
然后思考 的情况,其实只需要把两种方案拼起来就好了
用 个拼 的情况, 用剩下的 个和 的后两个最大的一共 个组成 个三角形
# Code
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n, m; cin >> n >> m;
if (m == n - 2) {cout << -1 << '\n'; return;}
int p = n - m;
vector<int> res(n + 1, 0);
int l = 1, r = p;
for (int i = p - 0; i >= 1; i -= 3) res[i] = r--;
for (int i = p - 1; i >= 1; i -= 3) res[i] = r--;
for (int i = p - 2; i >= 1; i -= 3) res[i] = l++;
for (int i = p + 1; i <= n; i++) res[i] = i;
for (int i = 1; i <= n; i++) cout << res[i] << " \n"[i == n];
return ;
}
int main() {
ios::sync_with_stdio(false);
int T; cin >> T;
while (T--) solve();
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# K - Haitang and Ava
# Question
Ava 会在直播开始时说一段开场白。
有效开场白的条件如下:
空字符串是有效的开场白。
如果是有效的开场白,那么和也是有效的开场白。
如果是有效的开场白,那么和也是有效的开场白。
任何不能用上述方法构造的字符串都不是有效的开场白。
给定一个字符串 ,你需要确定它是否是一个有效的开头语句。
# Solution
如果有 把 删去,有 把 删去,如果最后为一个空串,则是 Yes,否则是 No
# Code
#include <bits/stdc++.h>
using namespace std;
bool solve() {
string s; cin >> s;
while (!s.empty()) {
if (s.size() >= 5 && s.substr(0, 5) == "avava") s = s.substr(5);
else if (s.size() >= 3 && s.substr(0, 3) == "ava") s = s.substr(3);
else break;
}
return s.empty();
}
int main() {
ios::sync_with_stdio(false);
int T; cin >> T;
while (T--) cout << (solve() ? "Yes" : "No") << '\n
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19