Codeforces Round 1034 (Div. 3)

比赛链接如下:https://codeforces.com/contest/2123 

A. Blackboard Game

Initially, the integers from 00 to n−1 are written on a blackboard.

In one round,

  • Alice chooses an integer a on the blackboard and erases it;
  • then Bob chooses an integer b on the blackboard such that a+b≡3(mod4) and erases it.

Rounds take place in succession until a player is unable to make a move — the first player who is unable to make a move loses. Determine who wins with optimal play.

We define that x≡y(mod m) whenever x−y is an integer multiple of mm.

解题思路:

其实根据输入输出也能大概猜出来

(a+b-3)%4=0, Alice去拿一个数, 然后Bob去进行配对, 谁先操作不了, 谁就输了

eg:

n=4, 0 1 2 3

Alice拿0, Bob拿3进行配对

Alice拿1, Bob拿2进行配对

Bob赢

n=5, 0 1 2 3 4

这里Alice先拿0还是4无所谓,

Alice赢

n=8 0 1 2 3 ; 4 5 6 7

Bob赢

n%4==0, Bob赢

n%4!=0, Alice赢

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
    ll n;
    cin >> n;
    if (n % 4 == 0) {
        cout << "Bob" << endl;
    } else {
        cout << "Alice" << endl;
    }
}
int main() {
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

 B. Tournament

You are given an array of integers a1,a2,…,an. A tournament is held with nn players. Player i has strength aiai.

While more than k players remain,

  • Two remaining players are chosen at random;
  • Then the chosen player with the lower strength is eliminated. If the chosen players have the same strength, one is eliminated at random.

Given integers j and k (1≤j,k≤n), determine if there is any way for player j to be one of the last k remaining players.

解题思路:

当k=1时, aj要想留下来, 只能是数组最大值, 

k>1时, aj肯定是能留下来的

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
    int n, j, k;
    cin >> n >> j >> k;
    j--;
    vector<int> a(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    if (k == 1) {
        int mx = *max_element(a.begin(), a.end());
        if (a[j] == mx) {
            cout << "YES" << endl;
        } else {
            cout << "NO" << endl;
        }
    } else {
        cout << "YES" << endl;
    }
}
int main() {
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

 C. Prefix Min and Suffix Max

You are given an array aa of distinct integers.

In one operation, you may either:

  • choose a nonempty prefix of aa and replace it with its minimum value, or
  • choose a nonempty suffix of aa and replace it with its maximum value.

Note that you may choose the entire array a.

For each element ai, determine if there exists some sequence of operations to transform aa into [ai]; that is, make the array a consist of only one element, which is aiai. Output your answer as a binary string of length nn, where the ii-th character is 1 if there exists a sequence to transform aa into [ai], and 0 otherwise.

A prefix of an array is a subarray consisting of the first kk elements of the array, for some integer k.

A suffix of an array is a subarray consisting of the last k elements of the array, for some integer k.

给你一个不同整数的数组。
在一个操作中,您可以选择a的非空前缀*并将其替换为其最小值,或者选择a的非空前缀*并将其替换为其最大值。
注意,您可以选择整个数组a。对于每个元素a¿,确定是否存在一些操作序列将a转换为[a´];
也就是说,使数组只包含一个元素,即a。将您的答案输出为长度为n的二进制字符串,如果存在将a转换为[ai]的序列,则第i个字符为1,否则为0。
对于整数k,数组的前缀是由数组的前k个元素组成的子数组。数组的后缀是由数组的最后k个元素组成的子数组。 

解题思路:

​​​​​​1.前缀最小值:元素 ai 是从数组开头到 i 位置(a1 到 ai)的最小值。

2.后缀最大值:元素 ai 是从 i 位置到数组结尾(ai 到 an)的最大值。

3.可保留条件:如果 ai 是前缀最小值或后缀最大值,则存在操作序列将数组缩减为 [ai];否则,无法保留。

eg: 数组 [1, 3, 5, 4, 7, 2],输出 100011

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
    int n;
    cin >> n;
    vector<int> a(n + 1), pre(n + 1, INT_MAX), suf(n + 2);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        pre[i] = min(pre[i - 1], a[i]);
    }
    for (int i = n; i >= 1; i--) {
        suf[i] = max(suf[i + 1], a[i]);
    }
    for (int i = 1; i <= n; i++) {
        cout << (a[i] == pre[i] || a[i] == suf[i] ? 1 : 0);
    }
    cout << endl;
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

 D. Binary String Battle

Alice and Bob are given a binary string s of length n, and an integer k (1≤k<n).

Alice wins if she is able to transform all characters of ss into zeroes. If Alice is unable to win in a finite number of moves, then Bob wins.

Alice and Bob take turns, with Alice going first.

  • On Alice's turn, she may choose any subsequence∗∗ of length k in s, then set all characters in that subsequence to zero.
  • On Bob's turn, he may choose any substring†† of length k in ss, then set all characters in that substring to one.

Note that Alice wins if the string consists of all zeros at any point during the game, including in between Alice's and Bob's turns.

Determine who wins with optimal play.

∗∗A subsequence of a string s is a set of characters in s. Note that these characters do not have to be adjacent.

††A substring of a string s is a contiguous group of characters in s. Note that these characters must be adjacent.

解题思路:

1.Alice必赢的条件:
如果初始 cnt(s 中 1 的数量) ≤ k,Alice 一次就能把所有 1 清掉 —— 赢。
如果 n < 2*k,则 Bob 无法每次维护 cnt > k 的策略(因为没地方藏一个"额外的 1")—— Alice 
2. Bob必赢的条件:
如果 cnt > k 且 n ≥ 2*k,Bob 总能维护至少一个额外的 1,并总能抵消 Alice 的操作 —— 赢。 

因为你要找两个不重叠的长度为 k 的子串,至少需要长度 2k

否则他怎么也得和 Alice 的[清除区]发生重叠,Alice 就能全清了

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve(){
    int n, k, cnt = 0;
    string s;
    cin >> n >> k >> s;
    for(char c : s){
        if(c == '1'){
            cnt++;
        }
    }
    cout << (cnt <= k || n < 2*k ? "Alice" : "Bob") << '\n';
}
 
int main(){
    int t;
    cin >> t;
    while(t--) {
        solve();
    }
    return 0;
}

E. MEX Count

Define the MEX (minimum excluded value) of an array to be the smallest nonnegative integer not present in the array. For example,

  • MEX([2,2,1])=0 because 0 is not in the array.
  • MEX([3,1,0,1])=2 because 0 and 1 are in the array but 2 is not.
  • MEX([0,3,1,2])=4 because 0, 1, 2, and 3 are in the array but 44 is not.

You are given an array aa of size n of nonnegative integers.

For all k (0≤k≤n), count the number of possible values of MEX(a) after removing exactly kk values from a.

解题思路:MEX是数组a中的最小非负整数

eg:

数组a: 

0 1 2 3 4 5 .. n

出现次数分别为:

1 2 1 3 0 2 .. 5

比如MEX=1, 我们最少需要删除2个1

最多为n-1 (1之前每个数字次数剩1个,1后面全删了,最后剩1个数字,删除n-1个)

就是你删除任意个[cntx, n-x] 都能得到x

题目是删除k个数字, mex的可能性

然后差分即可

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> a(n), cnt(n + 1, 0);
        for (int i = 0; i < n; i++) {
            cin >> a[i];
            if (a[i] <= n) {
                cnt[a[i]]++;
            }
        }
        vector<int> ok(n + 1, false);
        ok[0] = true;
        for (int m = 1; m <= n; m++) {
            ok[m] = ok[m - 1] && (cnt[m - 1] > 0);
        }
        vector<int> diff(n + 2, 0);
        for (int m = 0; m <= n; m++) {
            if (!ok[m])
                break;
            int L = cnt[m];
            int R = n - m;
            if (L <= R) {
                diff[L] += 1;
                diff[R + 1] -= 1;
            }
        }
        vector<int> ans(n + 1);
        int cur = 0;
        for (int k = 0; k <= n; k++) {
            cur += diff[k];
            ans[k] = cur;
        }
        for (int k = 0; k <= n; k++) {
            cout << ans[k] << (k == n ? '\n' : ' ');
        }
    }
    return 0;
}

 F. Minimize Fixed Points

Call a permutation∗ p of length nn good if gcd(pi,i)>1 for all 2≤i≤n. Find a good permutation with the minimum number of fixed points‡‡ across all good permutations of length n. If there are multiple such permutations, print any of them.

∗∗ A permutation of length nn is an array that contains every integer from 1 to n exactly once, in any order.

gcd(x,y) denotes the greatest common divisor (GCD) of x and y.

‡‡A fixed point of a permutation p is an index j (1≤j≤n) such that pj=j.

解题思路:

n=6,

1 4 6 2 5 3

1 2 3 4 5 6

gcd:

1 2 3 2 5 3

fixed points = 2

gcd(pi,i)>1, i>1

i=0, a[0]=1

当n=13,

质数2及其倍数为:2  4  6  8 10 12 

数左移一位, 就可以和下标形成 gcd(pi,i)=2

2 4 6 8 10 12

4 6 8 10 12 2

prime = 3

3 6 9 12

素数越大, 在1-n这个序列中, 倍数的出现次数越少  

prime=5

5 10

只能这两进行轮换, 因此我们从prime比较大 -> prime比较小

prime在比较大的数轮换过后, 后续就不需要进行轮换了

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAXN = 1000005;
vector<bool> isp(MAXN, true); // isp[i] = true 表示是素数
void init(int n) {
    isp[0] = isp[1] = false;
    for (int i = 2; i * i <= n; i++) {
        if (isp[i]) {
            for (int j = i * i; j <= n; j += i) {
                isp[j] = false;
            }
        }
    }
}

void solve() {
    int n;
    cin >> n;
    init(n);
    vector<int> a(n + 1, -1);
    vector<bool> vis(n + 1, false);
    for (int i = n / 2; i >= 2; i--) {
        if (!isp[i]) {
            continue;
        }
        vector<int> c;    收集所有 i 的倍数
        for (int j = i; j <= n; j += i) {
            if (vis[j]) {
                continue;
            }
            vis[j] = true;
            c.push_back(j);
        }
        // // 构造一个环:c[0]->c[1]->...->c[k-1]->c[0]
        for (int j = 0; j < c.size(); j++) {
            a[c[j]] = c[(j + 1) % c.size()];
        }
    }
    for (int i = 1; i <= n; i++) {
        cout << (a[i] == -1 ? i : a[i]) << " ";
    }
    cout << '\n';
}
int main() {
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

G. Modular Sorting

 You are given an integer m (2≤m≤5⋅105) and an array aa consisting of nonnegative integers smaller than m.

Answer queries of the following form:

  • 1 i x: assign ai:=x
  • 2 k: in one operation, you may choose an element aiai and assign ai:=(ai+k)(modm)a — determine if there exists some sequence of (possibly zero) operations to make a nondecreasing.

Note that instances of query 2 are independent; that is, no actual operations are taking place. Instances of query 1 are persistent.

a(modm) is defined as the unique integer bb such that 0≤b<m and a−b is an integer multiple of m.

An array a of size n is called nondecreasing if and only if ai≤ai+1 for all 1≤i<n.

解题思路:

(ai+k)%m 

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAXN = 1000100;
vector<bool> isp;
vector<int> primes;

void init(int top) {
    isp.assign(top + 1, true);
    isp[0] = isp[1] = false;
    for (int i = 2; i <= top; ++i) {
        if (isp[i])
            primes.push_back(i);
        for (int j = 0; j < (int)primes.size(); ++j) {
            int p = primes[j];
            if (i * p > top)
                break;
            isp[i * p] = false;
            if (i % p == 0)
                break;
        }
    }
}

map<int, int> factorize(int v) {
    map<int, int> res;
    for (int i = 0; i < (int)primes.size(); ++i) {
        int p = primes[i];
        if (1LL * p * p > v)
            break;
        int cnt = 0;
        while (v % p == 0) {
            cnt++;
            v /= p;
        }
        if (cnt)
            res[p] = cnt;
    }
    if (v > 1)
        res[v] = 1;
    return res;
}

vector<int> get_divisors(int v) {
    map<int, int> f = factorize(v);
    vector<int> res;
    res.push_back(1);
    for (map<int, int>::iterator it = f.begin(); it != f.end(); ++it) {
        int p = it->first, c = it->second;
        int sz = res.size();
        int base = 1;
        for (int i = 0; i < c; ++i) {
            base *= p;
            for (int j = 0; j < sz; ++j) {
                res.push_back(res[j] * base);
            }
        }
    }
    return res;
}

int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }

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

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

    vector<array<int, 3>> q(qn);
    for (int i = 0; i < qn; i++) {
        cin >> q[i][0];
        if (q[i][0] == 1) {
            cin >> q[i][1] >> q[i][2];
        } else {
            cin >> q[i][1];
        }
    }

    vector<int> res(qn, -1);
    vector<int> b(n);

    vector<int> divisors = get_divisors(m);
    for (int d_index = 0; d_index < (int)divisors.size(); ++d_index) {
        int d = divisors[d_index];
        for (int i = 0; i < n; i++) {
            b[i] = a[i] % d;
        }

        int sum = 0;
        for (int i = 0; i + 1 < n; i++) {
            if (b[i] > b[i + 1])
                sum++;
        }

        for (int i = 0; i < qn; i++) {
            if (q[i][0] == 1) {
                int w = q[i][1] - 1;
                int v = q[i][2];
                if (w - 1 >= 0 && b[w - 1] > b[w])
                    sum--;
                if (w + 1 < n && b[w] > b[w + 1])
                    sum--;
                b[w] = v % d;
                if (w - 1 >= 0 && b[w - 1] > b[w])
                    sum++;
                if (w + 1 < n && b[w] > b[w + 1])
                    sum++;
            } else {
                if (gcd(q[i][1], m) == d) {
                    res[i] = sum < m / d;
                }
            }
        }
    }

    for (int i = 0; i < qn; i++) {
        if (res[i] != -1) {
            cout << (res[i] ? "YES" : "NO") << '\n';
        }
    }
}

int main() {
    init(MAXN);
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

感谢大家的点赞和关注,你们的支持是我创作的动力!

 

### Codeforces Round 927 Div. 3 比赛详情 Codeforces是一个面向全球程序员的比赛平台,定期举办不同级别的编程竞赛。Div. 3系列比赛专为评级较低的选手设计,旨在提供更简单的问题让新手能够参与并提升技能[^1]。 #### 参赛规则概述 这类赛事通常允许单人参加,在规定时间内解决尽可能多的问题来获得分数。评分机制基于解决问题的速度以及提交答案的成功率。比赛中可能会有预测试案例用于即时反馈,而最终得分取决于系统测试的结果。此外,还存在反作弊措施以确保公平竞争环境。 ### 题目解析:Moving Platforms (G) 在这道题中,给定一系列移动平台的位置和速度向量,询问某时刻这些平台是否会形成一条连续路径使得可以从最左端到达最右端。此问题涉及到几何学中的线段交集判断和平面直角坐标系内的相对运动分析。 为了处理这个问题,可以采用如下方法: - **输入数据结构化**:读取所有平台的数据,并将其存储在一个合适的数据结构里以便后续操作。 - **时间轴离散化**:考虑到浮点数精度误差可能导致计算错误,应该把整个过程划分成若干个小的时间间隔来进行模拟仿真。 - **碰撞检测算法实现**:编写函数用来判定任意两个矩形之间是否存在重叠区域;当发现新的连接关系时更新可达性矩阵。 - **连通分量查找技术应用**:利用图论知识快速求解当前状态下哪些节点属于同一个集合内——即能否通过其他成员间接相连。 最后输出结果前记得考虑边界条件! ```cpp // 假设已经定义好了必要的类和辅助功能... bool canReachEnd(vector<Platform>& platforms, double endTime){ // 初始化工作... for(double currentTime = startTime; currentTime <= endTime ;currentTime += deltaT){ updatePositions(platforms, currentTime); buildAdjacencyMatrix(platforms); if(isConnected(startNode,endNode)){ return true; } } return false; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值