2043A - Coin Transformation

按题意模拟。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int main() {
int t;
cin >> t;

while (t--) {
ll x;
cin >> x;

ll ans = 1;
while (x > 3) {
x /= 4;
ans <<= 1;
}
cout << ans << endl;
}

return 0;
}

2043B - Digits(分类)

n!n! 次数字dd。所以,他得到了数字ddddddddddddddd…dddn!n! 位)。问某数字能够被从1199 的哪些奇数整除。

1 肯定有。

一个数是 5 的倍数等价于末位是 0 或 5,因此只能d=5d=5

3 和 9 都是看数码和。对于 3,要求3n!d3\mid n! \cdot d,如果dd 是 3 或 9 已经成立,否则需要3n!3\mid n!,这等价于n3n \geqslant 3;对于 9 也是类似分析,如果dd 是 9 已经成立,如果dd 是 3 或 6,需要3n!3\mid n!,这等价于n3n \geqslant 3,否则需要9n!9\mid n!,这等价于n6n \geqslant 6

7 需要一点技巧,注意到1001=711131001=7\cdot 11\cdot 13,而n3n \geqslant 3 时的数都是 1001 的倍数,所以n3n \geqslant 3 都可以,否则n=2n=2 时只能d=7d=7

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

int main() {
int t;
cin >> t;

while (t--) {
int n, d;
cin >> n >> d;

vector<int> res{ 1 };
if (n >= 3 || d % 3 == 0) {
res.push_back(3);
}
if (d == 5) {
res.push_back(5);
}
if (n >= 3 || d == 7) {
res.push_back(7);
}
if (n >= 6 || (n >= 3 && d % 3 == 0) || d == 9) {
res.push_back(9);
}

for (auto x : res) {
cout << x << " ";
}
cout << endl;
}

return 0;
}

2043C - Sums on Segments(模拟)

先考虑全为 1,-1。

1,-1 这些数表明,这些子串和是连续的,如果子串和最小值是ll,子串和最大值为rr,那么[l,r][l,r] 中所有数都是可以取到的。问题化为最大最小子串和问题。

如果有一个特殊数,这个数将整个数组分成两块,左右都是全为 1,-1,化为了上面的问题。再考虑包含这个特殊数的子串,子串和仍然是连续的,类似地分别找出左边和右边的最大最小子串就能确定范围[l,r][l,r]

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int main() {
int t;
cin >> t;

while (t--) {
int n;
cin >> n;

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

int p = 0;
for (int i = 0; i < n; i++) {
if (a[i] != 1 && a[i] != -1) {
p = i;
}
}

set<int> res;
res.insert(0);
int sum = 0;
int maxr = 0, minr = 0;
for (int i = p + 1; i < n; i++) {
sum += a[i];
maxr = max(maxr, sum);
minr = min(minr, sum);
}
sum = 0;
int maxl = 0, minl = 0;
for (int i = p - 1; i >= 0; i--) {
sum += a[i];
maxl = max(maxl, sum);
minl = min(minl, sum);
}
for (int i = minl + minr; i <= maxl + maxr; i++) {
res.insert(a[p] + i);
}

auto solve = [&](int l, int r) {
int maxsum = 0, maxx = -2e9;
for (int i = l; i < r; i++) {
maxsum += a[i];
maxx = max(maxx, maxsum);
if (maxsum < 0) {
maxsum = 0;
}
}
int minsum = 0, minn = 2e9;
for (int i = l; i < r; i++) {
minsum += a[i];
minn = min(minn, minsum);
if (minsum > 0) {
minsum = 0;
}
}
for (int i = minn; i <= maxx; i++) {
res.insert(i);
}
};

solve(0, p);
solve(p + 1, n);

cout << res.size() << endl;
for (auto x : res) {
cout << x << " ";
}
cout << endl;
}

return 0;
}

2043D - Problem about GCD(Guess 数论)

暴力能过。请参看 atcoder 题解

证明的一种方法是使用素数距离。在这个问题的约束条件下,15001500 个连续整数总是包含至少一个素数。因此,在(x,y)=(L,R),(L,R1),,(L,R1500)(x,y)=(L,R),(L,R-1),\cdots,(L,R-1500) 中,至少有一个满足gcd(x,y)=1\gcd(x,y)=1 。由此可见K1500K \leq 1500

事实上,KK 会比这个极限小得多。在R5,,RR-5, \cdots, R 中,总有一个数与3030 共乘,而在约束条件下,这个数总是与L,,L+16L, \cdots, L+16 中的某些数共乘。这就证明了K21K \leq 21 。使用 CRT 可以生成K=7K=7 的情况。

更加详细的证明:

给定1LR10181 \leq L \leq R \leq 10^{18}RL17R - L \geq 17 ,证明存在满足以下条件的(x,y)(x, y)

  • LxL+16L \leq x \leq L + 16
  • R5yRR - 5 \leq y \leq R
  • gcd(x,y)=1\gcd(x, y) = 1

特别是,可以证明存在(x,y)(x, y) ,即gcd(x,y)=1\gcd(x, y) = 1RL21yxRLR - L - 21 \leq y - x \leq R - L

首先,存在yy 这样的R5yRR - 5 \leq y \leq Rgcd(y,30)=1\gcd(y, 30) = 1 。这一点可以通过研究每个Rmod30R \mod 30 得到证实。

yy 的各个素因子按升序排列为p1,p2,,pkp_1, p_2, \ldots, p_k 。下列性质成立:

  • k12k \leq 12
  • p17p_1 \geq 7 (如果是k1k \geq 1 ,以下也类似)
  • p211p_2 \geq 11
  • p313p_3 \geq 13
  • p417p_4 \geq 17
  • p519p_5 \geq 19
  • p623p_6 \geq 23
  • p729p_7 \geq 29
  • p831p_8 \geq 31
  • p937p_9 \geq 37
  • p1041p_{10} \geq 41
  • p1143p_{11} \geq 43
  • p1247p_{12} \geq 47

这一点可以通过贪婪地选择除2,3,52, 3, 5 以外的质因数,使它们的乘积不超过101810^{18} 来验证。

nin_ipip_i 的倍数在L,,L+16L, \ldots, L + 16 范围内的个数。因为ni17/pin_i \leq \lceil 17 / p_i \rceil ,所以我们有

ni3+2+2+1+1+1+1+1+1+1+1+1=16\sum n_i \leq 3 + 2 + 2 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 = 16

因此,L,,L+16L, \ldots, L + 16 中存在一个不能被p1,,pkp_1, \ldots, p_k 中任何一个数整除的数。设这个数为xx 。那么(x,y)(x, y) 满足条件。

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

int main() {
int t;
cin >> t;

while (t--) {
ll l, r, d;
cin >> l >> r >> d;

r = r / d;
l = (l + d - 1) / d;

bool ok = false;
for (ll len = r - l; len >= 0; len--) {
for (ll j = l; j + len <= r; j++) {
if (gcd(j, j + len) == 1) {
l = j, r = j + len;
ok = true;
break;
}
}
if (ok) break;
}

if (!ok) {
cout << -1 << " " << -1 << endl;
} else {
cout << (l * d) << " " << (r * d) << endl;
}
}

return 0;
}

2043E - Matrix Transformation(建模 DAG)

问题等价于给两个大小为n×mn \times m 的 01 矩阵AABB,对矩阵AA 任意次操作:把一行变成 0 或把一列变成 1。判断是否能将AA 变成BB

如果变了,那 B 最后必然有一个全 0 行或者全 1 列,把这列删掉,递归处理;如果没变,则必然与 A 相同。用拓扑排序删东西。

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <bits/stdc++.h>
using LL = long long;
using namespace std;

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);

int t;
cin >> t;

while (t--) {
int n, m;
cin >> n >> m;

vector A(n, vector<int>(m));
vector B(n, vector<int>(m));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
cin >> A[i][j];
}
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
cin >> B[i][j];
}
}

bool ok = true;
for (int bit = 0; bit < 30; bit++) {
vector a(n, vector<int>(m));
vector b(n, vector<int>(m));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
a[i][j] = (A[i][j] >> bit) & 1;
b[i][j] = (B[i][j] >> bit) & 1;
}
}

vector<vector<int>> E(n + m);
vector<int> deg(n + m);
auto add = [&](int u, int v) {
E[u].push_back(v);
deg[v]++;
};
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
b[i][j] ? add(n + j, i) : add(i, n + j);
}
}
queue<int> Q;
for (int i = 0; i < n + m; ++i) {
if (!deg[i]) Q.push(i);
}
while (!Q.empty()) {
int u = Q.front(); Q.pop();
if (u < n) {
int i = u;
for (int j = 0; j < m; ++j) {
b[i][j] = a[i][j];
}
} else {
int j = u - n;
for (int i = 0; i < n; ++i) {
b[i][j] = a[i][j];
}
}
for (auto v : E[u]) {
if (--deg[v] == 0) Q.push(v);
}
}

for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (a[i][j] != b[i][j]) {
ok = false;
}
}
}
}
cout << (ok ? "Yes" : "No") << endl;
}

return 0;
}