牛客周賽 Round 57

PHarr發表於2024-08-28

A - 小紅喜歡1

#include<bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;
using i128 = __int128;

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

const int inf = INT_MAX / 2;


i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    for(int i = 1 , x ; i <= 5 ; i ++) {
        cin >> x;
        if(x == 1) cout << i;
    }
    return 0;
}

B - 小紅的樹切割

要切割的邊,端點一定同色。

#include<bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;
using i128 = __int128;

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

const int inf = INT_MAX / 2;


i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n;
    cin >> n;
    string s;
    cin >> s;
    int cnt = 0;
    for (int i = 1, x, y; i < n; i++) {
        cin >> x >> y, x--, y--;
        if(s[x] == s[y]) cnt ++;
    }
    cout << cnt;
    return 0;
}

C - 小紅的雙好數(easy)

二進位制下,一定只有 \(0\)\(1\)\(n\)進位制下,一定是\(10\)

#include<bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;
using i128 = __int128;

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

const int inf = INT_MAX / 2;

bool check(int x, int y) {
    while (x) {
        if (x % y > 1) return false;
        x /= y;
    }
    return true;
}


i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    i64 n;
    cin >> n;
    if (n == 1) cout << "YES\n2 3\n";
    else if (n == 2) cout << "NO\n";
    else cout << "YES\n2 " << n << "\n";
    return 0;
}

D - 小紅的線段

點可以分成三種,\(y > kx + b , y = kx + b , y < kx + b\)。然後需要有交點的,最優解是選擇一個大於的和一個小於的,其次是選擇一個大於(小於)和等於,最後是兩個等於,剩餘的情況怎麼連線都沒有交點,所以隨便連就好了。

#include<bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;
using i128 = __int128;

#define int i64

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

const int inf = INT_MAX / 2;

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, k, b;
    cin >> n >> k >> b;
    vi A, B, C;
    for (int i = 1, N = n * 2, x, y, yy; i <= N; i++) {
        cin >> x >> y;
        yy = k * x + b;
        if (y == yy) C.push_back(i);
        else if (y > yy) A.push_back(i);
        else B.push_back(i);
    }
    vector<pii> res;
    while (not A.empty() and not B.empty()) {
        res.emplace_back(A.back(), B.back());
        A.pop_back(), B.pop_back();
    }
    while (not A.empty() and not C.empty()) {
        res.emplace_back(A.back(), C.back());
        A.pop_back(), C.pop_back();
    }
    while (not C.empty() and not B.empty()) {
        res.emplace_back(C.back(), B.back());
        C.pop_back(), B.pop_back();
    }
    assert(C.size() % 2 == 0);
    for (int i = 1; i < C.size(); i += 2)
        res.emplace_back(C[i - 1], C[i]);

    cout << res.size() << "\n";
    for (auto &[x, y]: res) cout << x << " " << y << " Y\n";
    for (int i = 1; i < A.size(); i += 2)
        cout << A[i - 1] << " " << A[i] << " N\n";
    for (int i = 1; i < B.size(); i += 2)
        cout << B[i - 1] << " " << B[i] << " N\n";
    return 0;
}

E - 小紅的雙好數(hard)

列舉\(k2\)進位制下只有\(0,1\)的數,然後驗證\(k1\)進位制下即可。複雜度\(O(2^{18\times\log_{k2} 10})\)

#include<bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;
using i128 = __int128;

#define int i64

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

const int inf = INT_MAX / 2;

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int k1, k2;
    cin >> k1 >> k2;
    int N = 1e18;
    vi p(1, 1);
    while (p.back() * k2 <= N)
        p.push_back(p.back() * k2);

    auto check = [k1](int x) {
        if (x < 2) return false;
        while (x) {
            if (x % k1 > 1) return false;
            x /= k1;
        }
        return true;
    };

    auto dfs = [p, check, N](auto &&self, int x, int i) -> void {
        if (x > N) return;
        if (check(x)) {
            cout << "YES\n" << x << "\n";
            exit(0);
        }
        if (i == p.size()) return;
        self(self, x, i + 1);
        self(self, x + p[i], i + 1);
        return;
    };
    dfs(dfs, 0, 0);
    cout << "NO\n";
    return 0;
}

F - 小紅的陣列操作

每個陣列的最小值可以用std::multiset<int>維護。

字首最小值可以用線段樹維護。

#include<bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;
using i128 = __int128;

#define int i64

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

const int inf = INT_MAX / 2;


struct Node {
    int l, r, value;
    Node *left, *right;

    Node(int l, int r, int value, Node *left, Node *right) :
            l(l), r(r), value(value), left(left), right(right) {};
};

// 建樹
Node *build(int l, int r, const vi &arr) {
    if (l == r) return new Node(l, r, arr[l], nullptr, nullptr);
    int mid = (l + r) >> 1;
    Node *left = build(l, mid, arr), *right = build(mid + 1, r, arr);
    return new Node(l, r, min(left->value, right->value), left, right);
}

// 修改
void modify(int l, int r, int v, Node *cur) {
    if (l > cur->r || r < cur->l) return;
    if (l <= cur->l && r >= cur->r) {
        cur->value = v;
        return;
    }
    int mid = (cur->l + cur->r) >> 1;
    if (l <= mid) modify(l, r, v, cur->left);
    if (r > mid) modify(l, r, v, cur->right);
    cur->value = min(cur->left->value, cur->right->value);
    return;
}
// 查詢
int query(int l, int r, Node *cur) {
    if (l <= cur->l && r >= cur->r) return cur->value;
    int mid = (cur->l + cur->r) >> 1, res = inf;
    if (l <= mid) res = min(res, query(l, r, cur->left));
    if (r > mid) res = min(res, query(l, r, cur->right));
    return res;

}

void modify(int x, int v, Node *cur) {
    modify(x, x, v, cur);
}

int query(int x, Node *cur) {
    return query(1, x, cur);
}

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n;
    cin >> n;
    vector<vi> a(n + 1);
    vector<multiset<int>> calc(n + 1);
    vi arr(n + 1);
    for (int i = 1, m; i <= n; i++) {
        cin >> m;
        a[i] = vi(m + 1);
        for (int j = 1; j <= m; j++)
            cin >> a[i][j], calc[i].insert(a[i][j]);
        arr[i] = *calc[i].begin();
    }
    Node *root = build(1, n, arr);
    int q;
    cin >> q;
    for (int opt, i, j, x; q; q--) {
        cin >> opt;
        if (opt == 1) {
            cin >> i >> j >> x;
            calc[i].erase(calc[i].find(a[i][j]));
            a[i][j] = x, calc[i].insert(x);
            if (*calc[i].begin() != arr[i])
                arr[i] = *calc[i].begin(), modify(i, arr[i], root);
        } else {
            cin >> i;
            cout << query(i, root) << "\n";
        }
    }
    return 0;
}

G - 小紅的雙排列構造

在大多數情況下是存在無解的情況,大致的構造思路是

\[1,2,3\dots,n,1,2,3,\dots, k - 2 , n , n - 1 , n - 2 , \dots,k - 1 \]

下面說一下幾種特例。

  • \(n=1\)時,只有\(1,1\)一種情況
    • \(k = 2\)時,\(1,1\)是唯一解
    • 其他情況均無解
  • \(n=2\)
    • \(k=1\)時,\(1,1,2,2\)
    • \(k=2\)時,\(1,2,2,1\)
    • \(k=3\)時,\(1,2,1,2\)
    • 其他情況無解
  • 其他情況下,不會出現無解的情況,但依舊有特例
    • \(k=0\)時,\(1,1,2,2,3,3\dots,n,n\)
    • \(k = 1\)時,\(1,1,2,3,\dots,n,2,3,4,\dots,n\)
    • \(k=2\)時,\(1,2,3,\dots,n,n,n-1,n-2,n-3,\dots,1\)
#include<bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;
using i128 = __int128;

#define int i64

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

const int inf = INT_MAX / 2;

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, k;
    cin >> n >> k;
    if (n == 1) {
        if (k == 2) cout << "1 1";
        else cout << "-1";
    } else if (n == 2) {
        if (k == 1)cout << "1 1 2 2";
        else if (k == 3) cout << "1 2 1 2";
        else if (k == 2) cout << "1 2 2 1";
        else cout << "-1";
    } else if (k == 0) {
        for (int i = 1; i <= n; i++)
            cout << i << " " << i << " ";
    } else if (k == 1) {
        cout << 1 << " ";
        for (int i = 1; i <= n; i++)
            cout << i << " ";
        for (int i = 2; i <= n; i++)
            cout << i << " ";
    } else if (k == 2) {
        for (int i = 1; i <= n; i++)
            cout << i << " ";
        for (int i = n; i >= 1; i--)
            cout << i << " ";
    } else {
        for (int i = 1; i <= n; i++)
            cout << i << " ";
        for (int i = 1; i <= k - 2; i++)
            cout << i << " ";
        for (int i = n; i > k - 2; i--)
            cout << i << " ";
    }
    return 0;
}