比赛链接
https://codeforces.com/gym/624051
题目及题解
A 题
https://codeforces.com/contest/1674/problem/A
问题分析
题目要求找到满足特定条件的整数$ a $和$ b $,核心是理解题目中的过程可以重新表述为 “用$ ab $乘以$ x $”。根据数学性质,$ x \cdot ab $必然能被$ x $整除,因此若$ y $不能被$ x $整除,则不存在符合条件的$ a $和$ b $;若$ y $能被$ x $整除,则可以简单地令$ a=1 $且$ b=y/x $。
代码实现
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
|
//#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define endl "\n"
#define int long long
using namespace std;
const int N = 1e6+10;
const int inf = 1e18+10;
void solve()
{
int x,y;cin >> x >> y;
int a = y/x;
if(y%x)
{
cout << 0 << " " << 0 << endl;
return;
}
cout << 1 << " " << a << endl;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int _ = 1;
cin >> _;
while(_--)
{
solve();
}
return 0;
}
|
B 题
https://codeforces.com/gym/105423/problem/C
问题分析
本题需要比较乘积的大小,直接计算可能会因数值过大而溢出。可以通过对乘积式子取对数,将乘法运算转化为加法运算来比较大小。也可以使用高精度计算或利用 2024 与 2048 的关系(因为$ (2024/2048)^{50} > 0.5 $)通过 2 的幂次比较。
代码实现
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
|
//#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define endl "\n"
#define int long long
using namespace std;
const int N = 1e6+10;
const int inf = 1e18+10;
int n;
void solve()
{
int sum = 0;
cin >> n;
for(int i=1;i<=n;i++)
{
int a;cin >> a;
sum += log2(a);
}
cout << ceil(sum*1.0/log2(2024)) << endl;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int _ = 1;
//cin >> _;
while(_--)
{
solve();
}
return 0;
}
|
C 题
https://codeforces.com/gym/105257/problem/F
问题分析
题目中提到代码可以重复提交,要获得最高得分,最优策略显然是每次都提交得分最高的代码,因此只需遍历数组找到最大值并输出即可。
代码实现
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
|
//#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define endl "\n"
#define int long long
using namespace std;
const int N = 1e6+10;
const int inf = 1e18+10;
void solve()
{
int n;cin >> n;
int mx = -1;
for(int i=1;i<=n;i++)
{
int t;cin >> t;
mx = max(mx,t);
}
cout << mx << endl;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int _ = 1;
cin >> _;
while(_--)
{
solve();
}
return 0;
}
|
D 题
https://codeforces.com/contest/1772/problem/D
问题分析
要使
$ |a_1 - x| \le |a_2 - x| \le \cdots \le |a_n - x| $
成立,只需考虑相邻两项的约束。
对每个$ i=1,2,\dots,n-1 $:$ |a_i - x| \le |a_{i+1} - x| $
等价于
$ (a_i - x)^2 \le (a_{i+1} - x)^2 \implies 2x(a_{i+1} - a_i) \le (a_{i+1}^2 - a_i^2) \implies 2x(a_{i+1} - a_i) \le (a_{i+1} - a_i)(a_{i+1} + a_i) $
如果$ a_{i+1} > a_i $,两边同除以正数$ (a_{i+1} - a_i) $,得$ 2x \le a_i + a_{i+1} \implies x \le \left\lfloor \frac{a_i + a_{i+1}}{2} \right\rfloor $
如果$ a_{i+1} < a_i $,除以负数要反向不等号,得$ 2x \ge a_i + a_{i+1} \implies x \ge \left\lceil \frac{a_i + a_{i+1}}{2} \right\rceil $
如果$ a_{i+1} = a_i $,则毫无限制。
把所有$ i $的约束合并,就是求一个整数区间$ [L, R] $:
- 初始化$ L = -\infty, R = +\infty $。
- 遍历$ i=1\ldots n-1 $:若$ a_i < a_{i+1} $,令$ R = \min\left(R, \left\lfloor \frac{a_i + a_{i+1}}{2} \right\rfloor \right) $
若$ a_i > a_{i+1} $,令$ L = \max\left(L, \left\lceil \frac{a_i + a_{i+1}}{2} \right\rceil \right) $
若$ L \le R $,区间非空,任选一个$ x \in [L, R] $(比如$ x = L $)即可;否则无解,输出$ -1 $。
代码实现
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
|
//#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define endl "\n"
#define int long long
using namespace std;
const int N = 1e6+10;
const int inf = 1e18+10;
void solve()
{
int n;
cin >> n;
vector<int> a(n);
for(int i= 0;i<n;i++) cin >> a[i];
int l = 0, r = 1e9;
for(int i=0;i<n-1;i++)
{
if(a[i]<a[i+1])
{
int nr = (a[i]+a[i+1]) / 2;
r = min(r,nr);
}
else if(a[i]>a[i+1])
{
int nl = ceil((a[i]+a[i+1])*1.0/2);
l = max(l,nl);
}
if(l>r)
{
cout << -1 << endl;
return;
}
}
cout << l << endl;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int _ = 1;
cin >> _;
while(_--)
{
solve();
}
return 0;
}
|
E 题
https://codeforces.com/contest/2051/problem/E
问题分析
本题可设计时间复杂度为$ O(n^2) $的解法,通过检查$ a $和$ b $并集中的整数作为可能价格来优化。采用事件处理(扫描线算法),按升序处理所有可能价格,维护树的购买数量和负面评价数量,更新答案。
代码实现
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;
int main() {
ios::sync_with_stdio(false); cin.tie(0);
int t;
cin >> t;
while (t--) {
int n, k;
cin >> n >> k;
vector<int> a(n), b(n);
for (auto &x : a) cin >> x;
for (auto &x : b) cin >> x;
vector<pair<int, int>> ev;
for (int i = 0; i < n; ++i) {
ev.emplace_back(a[i], 1);
ev.emplace_back(b[i], 2);
}
sort(ev.begin(), ev.end());
long long ans = 0;
int cnt = n, bad = 0;
for (int i = 0; i < 2 * n;) {
auto [x, y] = ev[i];
if (bad <= k) ans = max(ans, x * 1LL * cnt);
while (i < 2 * n && ev[i].first == x) {
bad += (ev[i].second == 1);
bad -= (ev[i].second == 2);
cnt -= (ev[i].second == 2);
++i;
}
}
cout << ans << '\n';
}
}
|
F 题
https://codeforces.com/gym/105386/problem/E
问题分析
给定正整数序列$ a_1, a_2, \cdots, a_n $与非负整数$ k $,可以执行至多一次操作:选择一个连续子数组,并把所有元素加$ k $。最大化整个序列的最大公因数。$ n \le 3 \times 10^5 $,$ k \le 10^{18} $。
假设选择的区间是$ [l, r] $,那么整个序列的最大公因数就是以下四项的最大公因数:
$
\gcd(a_1, a_2, \cdots, a_{l-1}), \gcd(|a_l - a_{l+1}|, |a_{l+1} - a_{l+2}|, \cdots, |a_{r-1} - a_r|), a_r + k, \gcd(a_{r+1}, a_{r+2}, \cdots, a_n)
$
如果$ r $的值是确定的,那么后两项的值都是确定的。接下来考虑$ l $的值如何影响前两项。
- 注意到前缀$ \gcd $的值只有$ \log X $种。
- 而且因为$ r $是确定的,所以$ l $越大,第二项越大,且变大后是之前的倍数。
所以对于固定的前缀$ \gcd $,$ l $越大越好。因此枚举$ \log X $个前缀$ \gcd $即将变小的地方,再枚举所有$ r $即可。含计算$ \gcd $的复杂度,均摊后$ O(n \log X) $。
代码实现
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
|
#include <bits/stdc++.h>
using i64 = long long;
i64 gcd(i64 x, i64 y) {
if (x == 0) return y;
if (y == 0) return x;
return std::gcd(x, y);
}
void Solve() {
int n;
i64 K;
std::cin >> n >> K;
std::vector<i64> a(n + 1);
for (int i = 1; i <= n; ++i) std::cin >> a[i];
std::vector<i64> g(n + 1), suf(n + 2);
for (int i = 1; i <= n; ++i) g[i] = gcd(g[i - 1], a[i]);
for (int i = n; i > 0; --i) suf[i] = gcd(suf[i + 1], a[i]);
i64 ans = g[n];
for (int i = 1; i <= n; ++i)
if (g[i] != g[i - 1]) {
i64 gc = g[i - 1];
for (int j = i; j <= n; ++j) {
gc = gcd(gc, a[j] + K);
ans = std::max(ans, gcd(gc, suf[j + 1]));
}
}
std::cout << ans << '\n';
}
int main() {
std::ios_base::sync_with_stdio(false);
std::cin.tie(nullptr);
int t;
std::cin >> t;
for (int ti = 1; ti <= t; ++ti) {
Solve();
}
return 0;
}
|