CF Round1034 A-E

第二次打div.3,还是太菜了QAQ:

A-Blackboard Game:

数学题,由于Bob每次要找与Alice相加能模4为3的数。
所以我们在输入时统计模四不同的结果的数量。

模4为3的组合有 \({0,3}\ {1,2}\) ,所以我们只需要统计这两个组合中的两个数是否相等,
如果相等,则Bob获胜(因为能刚好凑完),否则就是Alice获胜。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
int t,n;
int main(){
    cin >> t;
    while(t--){
        cin >> n;
        int cnt[5] = {};
        for(int i = 0; i < n; i++)
            cnt[i % 4]++;
        cout<<(cnt[0] == cnt[3] && cnt[1] == cnt[2] ? "Bob" : "Alice")<<'\n';
    }
    return 0;
}

B-Tournament:

贪心,考虑对旗手 \(j\) 最有利的情况,比自己实力高的混战,最后最大的留下来。
自己则把比自己菜的解决掉,最后剩下自己和最厉害的,如果还不小于等于 \(k\) 则给出no。

要考虑自己是最厉害的情况,直接输出yes。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
int t,n,j,k,a[200005];
int main(){
    cin >> t;
    while(t--){
        cin >> n >> j >> k;
        int dj = 0,tmp = 0,tmp2 = 0;
        for(int i = 1;i <= n;i++)
            cin >> a[i];
        j = a[j];
        sort(a + 1,a + n + 1);
        for(int i = n;i > 0;i--){
            if(a[i] == j){
                tmp = i;
                break;
            }
        }
        tmp2 = n - tmp;
        if(tmp == n){cout<<"YES"<<'\n'; //特判
        }else if(n - tmp2 + 1 <= k){cout<<"YES"<<'\n';
        }else{
            if(n - tmp2 - tmp + 2 <= k) cout<<"YES"<<'\n';
            else cout<<"NO"<<'\n';
        }
    }
    return 0;
}

C-Prefix Min and Suffix Max:

由于题中的两项操作都与最值有关系,我们不妨考虑一下 \(a_i\) 为不同值的情况:

\(a_i\)\(a\) 中的后缀最大值前缀最小值时,由于两种操作
都可以选择整个数组,所以是成立的。当为最大值时,可以挑选为整个数组的后缀。
而当为最小值时,则挑选整个数组作为前缀.

\(a_i\) 不是 \(a\) 中的后缀最大值前缀最小值时,定义 \(a_p\)\(\{a_1,a_2,...,a_i\}\)的最小值,
\(a_s\)\(\{a_i,a_{i + 1},...,a_n\}\) 的最大值,定义满足 \(p < i < s,a_p < a_i < a_s\) .

在保证不删除 \(a_i\) 的情况下,我们无法删除 \(a_p\)\(a_s\) .理由如下:

如果想要通过选取一段包含小于 \(a_p\) 的元素的前缀用来删除 \(a_p\) ,那么 \(a_i\) 就会被删除。
应为根据定义, \(a_p\)\(\{a_1,a_2,...,a_i\}\)的最小值,这意味着需要往 \(a_i\) 右边去寻找更小的元素,
\(a_i\) 并不是前缀最小值,所以会被一起删除。同理,如果想要找到一串后缀用来删除 \(a_s\) ,则需要到 \(a_i\) 左边寻找元素,
\(a_i\) 并不是后缀最大值,所以也会被一起删除.

综上所述,\(a_i\) 不可能在操作中被保留下来.

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int inf = 1e9 + 7;
int t,n;
void solve(){
    cin >> n;
    vector<int> a(n + 2),minn(n + 2,inf),maxn(n + 2); //使用vector动态分配空间
    for(int i = 1;i <= n;i++)
        cin >> a[i];
    for(int i = 1;i <= n;i++) minn[i] = min(minn[i - 1],a[i]);
    for(int i = n;i >= 1;i++) maxn[i] = max(maxn[i + 1],a[i]);
    for(int i = 1;i <= n;i++)
        cout<<(minn[i] == a[i] || maxn[i] == a[i] ? 1 : 0);
}
int main(){
    cin >> t;
    while(t--){
        solve();
        cout<<'\n';
    }
    return 0;
}

D-Binary String Battle:

结论题,设cnt为串中1的数量,如果满足 \(cnt \le k\)\(n < 2k\) ,则Alice赢,否则Bob赢.

点击查看代码
#include <bits/stdc++.h>
using namespace std;
int n,k;
void solve(){
    cin >> n >> k >> s;
    int cnt = 0;
    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();
}

E-MEX Count:

既然直接求复杂度太大,不妨往相反的方向想。
思考当 \(MEX\)\(0,1,...,n\) 的情况要删多少个数,分别计算出来在进行统计。

在计算过程中假设当前要使 \(MEX\) 变为 \(x\) ,那么删除数字的数量组成的集合是连续的。

对于一个数,想要使其变为 \(MEX\) ,至少要把自己在数组出现的所有地方都删除掉,
\(0~x-1\) 只剩一个的数字是不可删的,而剩余的数字是可删可不删的。

我们能决定删除数量的只有可删可不删这一类,而其数量是固定的,无论是删几个都符合题目的条件。

那么现在总共删除的数字中必须删除的为固定值,可删可不删的数量是连续的,那么总共删除的数量就是连续的。

现在问题就变为了多个区间相加的问题,可以用双指针解决.

区间左端点为必删的数量,右端是必删加上**所有可删可不删的数量(方便统计),即 \(n - 不可删的数量\left (MEX\right )\)

必删的数量可以提前预处理知道, \(MEX\) 也是可以枚举的,所以也能知道,这样左右端点都能求到,就没有什么问题了。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
int n;
void solve(){
    cin >> n;
    vector<int> a(n), ans(n+1), diff(n+2);
    map<int, int> freq;
    for(int i = 0; i < n; i++){
        cin >> a[i];
        freq[a[i]]++;
    }
    for(int i = 0; i <= n; i++){
        diff[freq[i]]++;
        diff[n - i + 1]--;
        if(!freq[i])
            break;
    }
    for(int k = 0; k <= n; k++){
        ans[k] = (k ? ans[k - 1] : 0) + diff[k];
        cout << ans[k] << (k != n ? ' ' : '\n');
    }
}
int main(){
    int t;
    cin >> t;
    while(t--){
      solve();
    }
    return 0;
}
posted @ 2025-07-15 16:43  Cai_hy  阅读(15)  评论(0)    收藏  举报