Refact.ai Match 1 (Codeforces Round 985)

A. Set

二分出最大数满足至少有\(k\)个倍数的数。

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

#define int i64

using vi = vector<int>;
using pii = pair<int, int>;

const i32 inf = INT_MAX / 2;

const int mod = 1e9 + 7;


void solve() { 
    int l, r, k;
    cin >> l >> r >> k;

    int L = l, R = r, res = -1;
    while(L <= R) {
        int mid = (L + R) / 2;
        int cnt = r / mid - (l - 1) / mid;
        if(cnt >= k) res = mid, L = mid + 1;
        else R = mid - 1;
    }
    if(res < l) cout << 0 << "\n";
    else cout << res - l + 1 << "\n";

    return ;
}

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int T;
    cin >> T;
    while(T --)
        solve();
    return 0;
}
 

有一个结论,这个数实际上就是\(\left\lfloor \frac {r}{k} \right\rfloor\)

#include <bits/stdc++.h>

using namespace std;


using i32 = int32_t;
using i64 = long long;


using vi = vector<int>;
using pii = pair<int,int>;

void solve(){
    int l, r, k;
    cin >> l >> r >> k;
    cout << max(0, r / k - l + 1) << "\n";
    return ;
}

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

    int T;
    cin >> T;
    while(T --)
        solve();

    return 0;
}

B. Replacement

这题,相当于每次选择两个相邻且不同数字,然后删掉\(r_i\oplus 1\)。所以只要当前\(0,1\)的个数都大于\(0\)就一定有解。

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

#define int i64

using vi = vector<int>;
using pii = pair<int, int>;

const i32 inf = INT_MAX / 2;

const int mod = 1e9 + 7;


void solve() { 
    int n;
    string s, r;
    cin >> n >> s >> r;

    vi cnt(2);
    for(auto i : s)
        cnt[i - '0'] ++;
    
    for(int x; auto i : r){
        x = (i - '0') ^ 1;
        if(cnt[0] > 0 and cnt[1] > 0)
            cnt[x] --;
        else {
            cout << "NO\n";
            return;
        }
    }
    cout << "YES\n";
    return; 
}

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int T;
    cin >> T;
    while(T --)
        solve();
    return 0;
}
 

C. New Rating

一个比较神秘的 dp 题。

\(f[i][0]\)表示到\(i\)为止前缀全部都选的得分。

\(f[i][1]\)表示\(f[i][0]\)的前缀最大值。

\(f[i][2]\)表示到\(i\)且已经舍弃一个区间的最大值。

对于\(f[i][2]\)有两种转移,一种是从之前已经\(f[i-1][2]\)转移,这种是直接接在之前已经舍弃过区间的情况。还有一种是从\(f[i-1][1]\)转移,也就是当前就要舍弃区间的情况。

有一种情况是一个区间都不用舍弃的情况,此时随便舍弃一个也就是答案为\(n-1\)

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

#define int i64

using vi = vector<int>;
using pii = pair<int, int>;

const i32 inf = INT_MAX / 2;

const int mod = 1e9 + 7;


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

    vi cnt(3);

    for(int i = 1, x, p; i <= n; i++) {
        cin >> x;
        if(x > cnt[0]) cnt[0] ++;
        else if(x < cnt[0]) cnt[0] --;

        if(x > cnt[2]) cnt[2] ++;
        else if(x < cnt[2]) cnt[2] --;

        p = cnt[1];
        if(x > p) p ++;
        else if(x < p) p --;

        cnt[2] = max(cnt[2], p);
        cnt[1] = max(cnt[1], cnt[0]);
    }
    cout << min(n - 1, ranges::max(cnt)) << "\n";
    return; 
}

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int T;
    cin >> T;
    while(T --)
        solve();
    return 0;
}
 

D. Cool Graph

只要一个点\(x\)的度数大于二,我们任选两个与\(x\)相邻的点\(y,z\)。执行一次操作,至少会使得边的的数量减\(1\),因此这个操作至多执行\(m\)次。

这个操作执行完后,会有两种情况。如果没有边了,则符合条件直接结束。

否则剩下的情况一定是一些孤立的边和孤立的点。我们可以任意选择一条边\((a,b)\),然后对于剩下的孤立边\((x,y)\),我们对\((a,x,y)\)进行一次操作,则会把边\((x,y)\)断掉,并插到\(a\)上,最终会形成一个以\(a\)为中心的菊花图。对于孤立的点\(x\),我们可以执行一次操作\((a,b,x)\),这样就会把\(x\)插到\(a,b\)中间,如果还有孤立点,就插到\(a,x\)中间。最终图就会变成以\(a\)为中心的菊花图插着一条链。

总体操作次数上限是\((m - 1) + (n -1)\)

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

using vi = vector<int>;
using pii = pair<int, int>;

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

    vector<int> f(n + 1, -1);
    vector<array<int, 3>> res;

    auto add = [&](auto &&self, int x, int y) -> void {
        if (f[x] == y and f[y] == x) {
            f[x] = f[y] = -1;
        } else if (f[x] != -1) {
            int z = f[x];
            res.push_back({x, y, z});
            f[x] = f[z] = -1;
            self(self, y, z);
        } else if (f[y] != -1) {
            int z = f[y];
            res.push_back({x, y, z});
            f[y] = f[z] = -1;
            self(self, x, z);
        } else {
            f[x] = y, f[y] = x;
        }
        return;
    };

    for (int x, y; m; m--) {
        cin >> x >> y;
        add(add, x, y);
    }

    vector<pii> edge;
    for (int i = 1; i <= n; i++) {
        if (f[i] == -1) continue;
        if (f[i] < i) continue;
        edge.emplace_back(i, f[i]);
    }

    if (not edge.empty()) {
        auto [a, b] = edge[0];
        for (int i = 1; i < edge.size(); i++) {
            auto [x, y] = edge[i];
            res.push_back({a, x, y});
        }
        for (int i = 1; i <= n; i++) {
            if (f[i] != -1) continue;
            res.push_back({a, b, i});
            b = i;
        }
    }

    cout << res.size() << "\n";
    for(auto [x, y, z] : res)
        cout << x << " " << y << " " << z << "\n";
    return;
}

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

    int T;
    cin >> T;
    while (T--)
        solve();

    return 0;
}

E. Common Generator

我们首先求出每个数\(a_i\)最小质因子\(b_i\)

如果每一个数的最小质因子都不是本身,换句话说每一个数都不是质数,则每个数的次小质因子一定是大于等于\(2\)。也就是说对于每个数都存在\(2b_i \le a_i\)。并且

\[(2\times 1) \rightarrow (2 \times 2) \rightarrow \dots \rightarrow 2b_i \rightarrow 3b_i\rightarrow \dots \rightarrow a_i \]

这样的路径一定存在,所以\(2\)一定是答案。

剩下的情况就是存在一些数是质数。

首先我们要知道,任何一个质数一定不能按照题目的方法被构造。我们可以反证法,如果一个数\(a\)加上自己的因子\(b\)等于一个质数\(p\),则一定有

\[p = a + b = kb + b = (k + 1) b \]

\(p\)会有\((k+1)\)\(b\)这两个因子,不符合质数定义。

因此如果存在两种质数则一定无解。

那么,我们就必须要选择唯一出现的质数\(p\)作为答案,剩下就是我们要判断这个答案是否合法。

  1. 如果这个数是\(p\)的倍数,一定可以被构造

  2. 如果这个数小于\(2p\),一定不能被构造,无解。

  3. 如果这个数是偶数,则一定可以被构造,令\(a_i = 2k\),并且\(a_i \ge 2p\),则一定存在如下构造方法

    \[p \rightarrow 2p \rightarrow 2(p+1) \rightarrow 2(p+2) \rightarrow 2k = a_i \]

  4. 如果这个数减最小质因子大于等于\(2p\),则一定可以被构造。首先这个数奇数,且最小质因子一定是奇数,则这个数减最小质因子一定是这个偶数,并且是这个数一个因数,记为\(x\)。因为满足了\(x\ge 2p\),则一定可以用 3 的方法构造出\(x\),再构造出\(a_i\)

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

#define int i64

using vi = vector<int>;
using pii = pair<int, int>;

const i32 inf = INT_MAX / 2;

const int mod = 1e9 + 7;

const int N = 4e5;

vi minp;

void init() {
    minp = vi(N + 1, inf);
    for (int i = 2; i <= N; i++) {
        if (minp[i] != inf) continue;
        for (int j = i; j <= N; j += i)
            minp[j] = min(minp[j], i);
    }
    return;
}


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

    vi a(n);

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

    int must = -1;

    for (int i = 0; i < n; i++) {
        if (a[i] != minp[a[i]]) continue;
        if (must == -1) must = a[i];
        else if (must != a[i]) {
            cout << "-1\n";
            return;
        }
    }

    if (must == -1) {
        cout << "2\n";
        return;
    }

    for (int i = 0; i < n; i++) {
        if (a[i] % must == 0) continue;

        if (a[i] < must * 2) {
            cout << "-1\n";
            return;
        }

        if (a[i] % 2 == 0) continue;

        if (a[i] - minp[a[i]] < must * 2) {
            cout << "-1\n";
            return;
        }

    }
    cout << must << "\n";
    return;
}

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

    init();

    int T;
    cin >> T;
    while (T--)
        solve();
    return 0;
}
posted @ 2024-11-10 21:28  PHarr  阅读(88)  评论(0编辑  收藏  举报