2115A / 2116C - Gellyfish and Flaming Peony

先做出一个 GCD,再将其它数变成 GCD。

看到 5000 考虑O(n2)\mathcal O(n^{2}) 的 DP。设fi,xf_{i,x} 表示前ii 个数中至少需要选出几个数才能组合出 GCD 等于xx。复杂度O(nVlogV)\mathcal O(nV\log V)V=5000V=5000,能过。

1
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
#include <bits/stdc++.h>
using namespace std;

using uint = unsigned;
using ll = long long;
using ull = unsigned long long;
using ulll = unsigned __int128;

constexpr ll inf = 0x3f3f3f3f3f3f3f3f;

void solve() {
int n;
cin >> n;

vector<int> a(n);
int d = 0;
for (int i = 0; i < n; i++) {
cin >> a[i];
d = gcd(d, a[i]);
}

int cnt = 0;
int has_one = 0;
for (int i = 0; i < n; i++) {
cnt += a[i] != d;
if (a[i] == d) has_one = 1;
}

const int N = 5001;
vector<int> f(N, inf);
for (int i = 0; i < n; i++) {
auto nf = f;
nf[a[i]] = 0;
for (int j = 1; j < N; j++) {
nf[gcd(j, a[i])] = min(nf[gcd(j, a[i])], f[j] + 1);
}
f = nf;
}
cout << (f[d] + cnt - 1 + has_one) << endl;
}

int main() {
cin.tie(nullptr)->sync_with_stdio(false);

for (int t = (cin >> t, t); t--; )
solve();

return 0;
}

2115B / 2116D - Gellyfish and Camellia Japonica

大概想法是先找出必要条件,再验证充分性。

倒着求出每个数的下界(axaz, ayaza_{x} \geqslant a_z,\ a_{y} \geqslant a_{z}),取aa 为这个下界,再验证构造出的这个aa 是否合法。复杂度O(n+q)\mathcal O(n+q)

1
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
#include <bits/stdc++.h>
using namespace std;

void solve() {
int n, q;
cin >> n >> q;

vector<int> b(n);
for (int i = 0; i < n; i++) {
cin >> b[i];
}

vector<array<int, 3>> que(q);
for (auto& [x, y, z] : que) {
cin >> x >> y >> z;
x--, y--, z--;
}
reverse(que.begin(), que.end());

auto a = b;
for (auto& [x, y, z] : que) {
a[y] = max(a[y], a[z]);
a[x] = max(a[x], a[z]);
if (z != x && z != y) { // 特别注意这个判断
a[z] = 0;
}
}

reverse(que.begin(), que.end());
auto c = a;
for (auto& [x, y, z] : que) {
c[z] = min(c[x], c[y]);
}

if (b != c) {
cout << -1 << endl;
return;
}

for (int i = 0; i < n; i++) {
cout << a[i] << " ";
}
cout << endl;
}

int main() {
cin.tie(nullptr)->sync_with_stdio(false);

for (int t = (cin >> t, t); t--; )
solve();

return 0;
}

2115D / 2116F - Gellyfish and Forget-Me-Not - UPSOLVE

这题方法应该不少,写一个相对好理解的。

先置ai:=aibi,res:=resbia_{i}:=a_{i}\oplus b_{i},\mathrm{res}:=\mathrm {res}\oplus b_{i},这样相当于每个人可以选择要不要aia_{i}

考虑aa 只有 01 怎么做:最后一个拿到a=1a =1 的人有决定权,可以改成他想要的数。因此检查最后一个a=1a =1 的位置,如果是c=1c=1,那么答案为 1,否则答案为 0。

如果有多位,就要知道每一个二进制位的决定权在谁手上。倒序遍历(因为要找最后一个位置)aa 并插入线性基,设将aia_{i} 插入线性基后的最高位为2d2^{d},那么dd 的决定权就在cic_{i} 手上。

现在,从高到低遍历每个二进制位,这一位dd 的决定权在谁手上,这个人就能把这一位变成他想要的数(c=1c=1 则变成 1,否则变成 0)。

1
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
#include <bits/stdc++.h>
using namespace std;

using uint = unsigned;
using ll = long long;
using ull = unsigned long long;
using ulll = unsigned __int128;

constexpr int B = 60;

void solve() {
int n;
cin >> n;

vector<ull> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
ull res = 0;
for (int i = 0; i < n; i++) {
ull x;
cin >> x;
a[i] ^= x;
res ^= x;
}
string c;
cin >> c;

array<ull, B> h{}; // 线性基
array<bool, B> op{};
for (int i = n - 1; i >= 0; i--) {
auto& x = a[i];
for (int bit = B - 1; bit >= 0; bit--) {
if (x >> bit & 1) {
if (!h[bit]) {
op[bit] = c[i] - '0';
h[bit] = x;
break;
} else {
x ^= h[bit];
}
}
}
}
for (int bit = B - 1; bit >= 0; bit--) {
if (op[bit] ^ (res >> bit & 1)) {
res ^= h[bit];
}
}
cout << res << endl;
}

int main() {
cin.tie(nullptr)->sync_with_stdio(false);

for (int t = (cin >> t, t); t--; )
solve();

return 0;
}