Featured image of post DSA训练赛二题解(AI汇总)

DSA训练赛二题解(AI汇总)

题解

比赛链接

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] $:

  1. 初始化$ L = -\infty, R = +\infty $。
  2. 遍历$ 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;
}
本作品采用知识共享署名-非商业性使用-相同方式共享4.0国际许可协议进行许可(CC BY-NC-SA 4.0)
文章浏览量:Loading
Powered By MC ZBD Studio
发表了43篇文章 · 总计69.19k字
载入天数...载入时分秒...
总浏览量Loading | 访客总数Loading

主题 StackJimmy 设计
由ZephyrBD修改