2024牛客暑期多校训练营3

B Crash Test

思路:

a的任意倍数与b的任意倍数的和 都是 a和b的最大公约数的倍数

如果选一次操作,最近的距离为min(D % h[i],h[i] - D % h[i])

那么多次操作的最近距离即为min(D % gcd_h,gcd_h - D % gcd_h)

void solve() {
    int n, D;
    cin >> n >> D;
    int h = 0;
    for (int i = 1; i <= n; ++i) {
        int x;
        cin >> x;
        h = gcd(x, h);
    }
    cout << min(D % h, h - D % h);
}

L Sudoku and Minesweeper

思路:

由于不能替换所有数字,那就只存在一个数字即可,发现一定可以找到一个8满足条件


void solve() {
    vector<string> ve(10);
    for (int i = 1; i <= 9; ++i) {
        cin >> ve[i];
        ve[i] = ' ' + ve[i];
    }
    int x = 0, y = 0;
    for (int i = 2; i <= 8; ++i) {
        for (int j = 2; j <= 8; ++j) {
            if (ve[i][j] == '8') {
                x = i, y = j;
                break;
            }
        }
        if (x && y) break;
    }

    for (int i = 1; i <= 9; ++i) {
        for (int j = 1; j <= 9; ++j) {
            if (i == x && j == y) cout << ve[i][j];
            else cout << '*';
        }
        cout << '\n';
    }

}

 A Bridging the Gap 2

思路:

首先计算运完所有人需要往返的次数s = (n - r)/ (r - l)  (上取整),一次往返需要l个人,所以需要s*l个人来往返

并且可以求出每个人可以往返的次数为(h - 1)/ 2

同时一个人往返的次数不能超过s

那么可以求出所有人的往返次数总和

通过比较所有人的往返次数总和与需要的往返次数s*l来判断是否可以

 

void solve() {
    int n, l, r;
    cin >> n >> l >> r;
    int s = (n - r + r - l - 1) / (r - l);
    int sum = 0;
    for (int i = 1; i <= n; ++i) {
        int h;
        cin >> h;
        h --;
        h /= 2;
        sum += min(h, s);
    }
    if (sum >= s * l) {
        cout << "Yes";
    } else cout << "No";
}

D Dominoes!

思路:

首先可以将骨牌按x和y是否相同分为两类

对于x和y不相同的情况,当有一个骨牌x1和y1,一个骨牌x2和y2,若y1等于x2,那么就交换x2和y2,并且y2一定不等于y1,以此方法可以对所有x不等于y的骨牌进行排列

接下来就是对x和y相同的情况,对于两个不同的骨牌xx和yy,可以将其合并为xxyy,那么就可以看成是x和y不相同的骨牌,以此方法对所有x和y相同的骨牌进行合并,最后最多只会剩下一种骨牌

如果最后还剩下一种骨牌,那么考虑把骨牌塞进已有有排列骨牌里,只要当前塞的位置前后骨牌与其不相等就塞,若最后还没塞完那就不存在解

这里已有的骨牌序列里相邻的骨牌都不相等,与剩下的这种骨牌一样的骨牌相邻的位置一定都不能塞,那么就与顺序没有关系,所以直接往里塞来判断的方法是可行的

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define PII pair<int, int>
const int N = 1e5 + 5, mod = 998244353, Mod = 1e9 + 7, inf = 1e18;

struct E {
    int l, r;
};

void solve() {
    int n;
    cin >> n;
    map<int, int> cnt;
    vector<E> ve;
    for (int i = 1; i <= n; ++i) {
        int x, y;
        cin >> x >> y;
        if (x == y) {
            cnt[x] ++;
        }
        else {
            if(!ve.empty() && x == ve.back().r) swap(x, y);
            ve.push_back({x, y});
        }
    }
    priority_queue<PII> q;
    for (auto [x, y]:cnt) {
        q.push({y, x});
    }
    while (q.size() >= 2) {
        auto [c, x] = q.top();
        q.pop();
        auto [c1, x1] = q.top();
        q.pop();
        if (!ve.empty() && ve.back().r == x) ve.push_back({x1, x1}), ve.push_back({x, x});
        else ve.push_back({x, x}), ve.push_back({x1, x1});
        c -- , c1 --;
        if (c > 0) q.push({c, x});
        if (c1 > 0) q.push({c1, x1});
    }

    int num = 0, id;
    if (q.size()) {
        auto [c, x] = q.top();
        q.pop();
        num = c, id = x;
    }
//    cerr << num << ' ' << id << '\n';
    vector<E> ans;
    if (num > 0 && (ve.empty() || (!ve.empty() && ve.front().l != id))) ans.push_back({id, id}), num --;
    for (int i = 0; i < ve.size(); ++i) {
        ans.push_back(ve[i]);
        if (num > 0 && i < ve.size() - 1 && ve[i].r != id && ve[i + 1].l != id) {
            ans.push_back({id, id});
            num --;
        }
    }
    if (num > 0 && !ve.empty() && ve.back().r != id) {
        ans.push_back({id, id}), num --;
    }

//    if (ans.size() == n) {
        cout << "Yes\n";
        for (auto [x, y]:ans) cout << x << ' ' << y << '\n';
//    } else cout << "No\n";

}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    int T = 1;
//    cin >> T;
    while (T--) {
        solve();
    }

    return 0;
}

J Rigged Games

思路:

首先对于每个a小局,可以用循环双指针O(n)的预处理出每个起点赢得一个小局的位置,并且是谁赢

对于每个b大局,由于从每个起点开始完成一个小局后的位置已知,可以通过O(n)的知道当前起点开始比赛的赢家,那么求所有的起点为O(n2),考虑优化

可以用倍增来做

to[i][j]表示从i开始进行2j小局后,进行下一小局的位置

cnt[i][j][0/1]表示从i开始进行了2j小局中,0/1赢得的大局数

预处理出to和cnt后,类似于倍增求lca,找到最远的位置,满足0和1赢得的大局数都小于b,那么下一小局将决定谁赢

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define PII pair<int, int>
const int N = 1e5 + 5, mod = 998244353, Mod = 1e9 + 7, inf = 1e18;

int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};



string s;
int n, a, b;
int to[N][33], cnt[N][33][2];

void solve() {
    cin >> n >> a >> b;
    cin >> s;
    int l = 0, r = 0;
    int now[2] = {0, 0};
    now[s[r] - '0'] ++;
    while (l < n) {
        if (now[0] >= a || now[1] >= a) {
            if (now[0] >= a) {
                cnt[l][0][0] = 1;
            } else {
                cnt[l][0][1] = 1;
            }
            to[l][0] = r + 1;
            now[s[l++] - '0'] --;
            continue;
        }
        r++;
        r %= n;
        now[s[r] - '0'] ++;
    }

    for (int i = 1; i <= 30; ++i) {
        for (int j = 0; j < n; ++j) {
            to[j][i] = to[to[j][i - 1]][i - 1];
            cnt[j][i][0] = cnt[j][i - 1][0] + cnt[to[j][i - 1]][i - 1][0];
            cnt[j][i][1] = cnt[j][i - 1][1] + cnt[to[j][i - 1]][i - 1][1];
        }
    }

    for (int i = 0; i < n; ++i) {
        now[0] = now[1] = 0;
        int pos = i;
        for (int j = 30; j >= 0; --j) {
            if (now[0] + cnt[pos][j][0] < b && now[1] + cnt[pos][j][1] < b) {
                now[0] += cnt[pos][j][0], now[1] += cnt[pos][j][1];
                pos = to[pos][j];
            }
        }
        cout << cnt[pos][0][1];
    }

}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    int T = 1;
//    cin >> T;
    while (T--) {
        solve();
    }

    return 0;
}

 

posted @ 2024-07-26 16:59  bible_w  阅读(30)  评论(0编辑  收藏  举报