Codeforces Round #767 (Div. 2) A - F

算法竞赛题解精选
本文提供了六道算法竞赛题目的解答思路与代码实现,包括排序、数学问题、字符串匹配、矩阵计算、动态规划等,旨在帮助读者理解算法原理并提高编程能力。

A

  • 排序即可
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while(t--){
        int n, k;
        cin >> n >> k;
        vector<pair<int, int> > a(n);
        for(auto &i : a) cin >> i.first;
        for(auto &i : a) cin >> i.second;
        sort(a.begin(), a.end());
        for(auto i : a){
            if(k >= i.first) k += i.second;
        }
        cout << k << '\n';
    }
    return 0;
}

B

给你一个从lllrrr的连续序列,可以对这个序列进行kkk次操作,每次操作可以选择两个数求乘积,得到结果放回原序列中,问能不能在kkk次操作以内让这个序列任意两项的gcd>1gcd>1gcd>1

  • 因为数字连续,所以我们选择222作为质因子,那么答案就是总的数字个数−-含有因子222的数字个数,也就是r−l+1−(r2−l−12)r-l+1-(\frac r 2-\frac{l-1}2)rl+1(2r2l1)
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while(t--){
        int l, r, k;
        cin >> l >> r >> k;
        if(l == r){
            if(l == 1) cout << "NO\n";
            else cout << "YES\n";
        }else{
            if(k >= r - l + 1 - (r / 2 - (l - 1) / 2)) cout << "YES\n";
            else cout << "NO\n";
        }
    }
    return 0;
}

C

给你一个数列,每次从中取出若干个数,求他们的mexmexmex并放入到bbb数组中,并把原来的数删去,让你求出一个字典序最大的bbb数组

  • 尽可能的让第一个数更大,找尽可能大的mexmexmex,用一个指针记录当前位置,消耗一个较大的数是没有影响的
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while(t--){
        int n;
        cin >> n;
        vector<int> a(n), cnt(n + 1);
        for(int i=0;i<n;i++){
            cin >> a[i];
            cnt[a[i]] += 1;
        }
        vector<bool> f(n + 1);
        queue<int> q;
        int p = 0;
        while(p < n){
            int now = 0;
            while(cnt[now] > 0){
                now += 1;
            }
            int num = 0;
            while(num < now){
                cnt[a[p]] -= 1;
                if(!f[a[p]] && a[p] < now){
                    num += 1;
                    f[a[p]] = true;
                }
                p += 1;
            }
            if(now == 0) p += 1;
            for(int i=0;i<now;i++){
                f[i] = false;
            }
            q.push(now);
        }
        cout << q.size() << '\n';
        while(!q.empty()){
            cout << q.front() << ' ';
            q.pop();
        }
        cout << '\n';
    }
    return 0;
}

D

让你从nnn个字符串里面找到若干字符串按照顺序拼接起来组成一个回文串,字符串长度都在3以内,问能不能拼出来

  • 显然如果字符串长度是1,那么它自己就是回文;如果字符串长度是2,那么可能和2或3两种情况构成回文;如果长度为3,那么可能和2和3两种情况构成回文,分别讨论即可
#include <bits/stdc++.h>

using namespace std;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while(t--){
        int n;
        cin >> n;
        bool ok = false;
        set<string> two, three;        
        for(int i=0;i<n;i++){
            string s;
            cin >> s;
            if(s.length() == 1) ok = true;
            else if(s.length() == 2){
                if(s[0] == s[1]) ok = true;
                else{
                    string ss = s;
                    reverse(ss.begin(), ss.end());
                    if(two.count(ss)) ok = true;
                    for(char i='a';i<='z';i++){
                        if(three.count(ss + i)) ok = true;
                    }
                    two.insert(s);
                }
            }else{
                if(s[0] == s[2]) ok = true;
                else{
                    string ss = s;
                    reverse(ss.begin(), ss.end());
                    ss.pop_back();
                    if(two.count(ss)) ok = true;
                    ss = s;
                    reverse(ss.begin(), ss.end());
                    if(three.count(ss)) ok = true;
                    three.insert(s);
                }
            }
        }
        cout << (ok ? "YES" : "NO") << '\n';
    }
    return 0;
}

E

给你一个n×nn\times nn×n的矩阵bbbbi,jb_{i,j}bi,j是由矩阵ai,ja_{i,j}ai,j的上下左右四个数取异或和得到的,现在求aaa矩阵的所有元素的异或和

  • 有一种很简单的方法,任意给定矩阵aaa的第一行,然后根据矩阵bbb,求出整个矩阵aaa,然后计算即可
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while(t--){
        int n;
        cin >> n;
        vector<vector<int> > a(n, vector<int>(n));
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                cin >> a[i][j];
            }
        }
        vector<vector<int> > res(n, vector<int>(n));
        int ans = 0;
        for(int i=1;i<n;i++){
            for(int j=0;j<n;j++){
                res[i][j] = a[i - 1][j];
                if(j >= 1) res[i][j] ^= res[i - 1][j - 1];
                if(j < n - 1) res[i][j] ^= res[i - 1][j + 1];
                if(i >= 2) res[i][j] ^= res[i - 2][j];
                ans ^= res[i][j];
            }
        }
        cout << ans << '\n';
    }
    return 0;
}

F1

alicealicealicebobbobbob玩游戏,一共有nnn个回合,起始成绩为000,每次alicealicealice选择一个[0,k][0,k][0,k]内的实数,bobbobbob可以选择加上或者减去,他至少要加mmm次,问最终的成绩期望

  • dp[i][j]dp[i][j]dp[i][j]为前iii个回合选择jjj次加法得到的成绩,那么显然有dp[i][j]=dp[i−1][j−1]+k+dp[i−1][j]−k=dp[i−1][j−1]+dp[i−1][j]dp[i][j]=dp[i-1][j-1]+k+dp[i-1][j]-k=dp[i-1][j-1]+dp[i-1][j]dp[i][j]=dp[i1][j1]+k+dp[i1][j]k=dp[i1][j1]+dp[i1][j]
  • 初始状态为dp[i][i]=i×kdp[i][i]=i\times kdp[i][i]=i×k
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const ll MOD = 1e9 + 7;
ll fastpow(ll base, ll power){
    ll ans = 1;
    while(power > 0){
        if(power & 1) ans = ans * base % MOD;
        base = base * base % MOD;
        power >>= 1;
    }
    return ans;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    ll inv = fastpow(2, MOD - 2);
    while(t--){
        int n, m, k;
        cin >> n >> m >> k;
        vector<vector<ll> > dp(n + 1, vector<ll> (m + 1));
        for(int i=1;i<=m;i++){
            dp[i][i] = 1ll * i * k % MOD;
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(i == j) continue;
                dp[i][j] = (dp[i - 1][j - 1] + dp[i - 1][j]) % MOD * inv % MOD;        
            }
        }
        cout << dp[n][m] << '\n';
    }
    return 0;
}

F2

  • 考虑从dp[i][j]dp[i][j]dp[i][j]dp[n][m]dp[n][m]dp[n][m]的转移,相当于从(i,j)(i,j)(i,j)(n,m)(n,m)(n,m)的路径数量,考虑每一行,我们已知的初始状态是dp[i][i]dp[i][i]dp[i][i],考虑从这个状态开始转移,但是dp[i][i]dp[i][i]dp[i][i]不能直接走到dp[i+1][i+1]dp[i+1][i+1]dp[i+1][i+1],所以控制第一步先让他到dp[i+1][i]dp[i+1][i]dp[i+1][i],然后就变成从(i+1,i)(i+1,i)(i+1,i)(n,m)(n,m)(n,m)的路径数量,应该是Cn−i−1m−iC_{n-i-1}^{m-i}Cni1mi,因为每一次都会除以2,所以最终统计出答案还要除以2n−i2^{n-i}2ni
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const ll MOD = 1e9 + 7;
ll fastpow(ll base, ll power){
    ll ans = 1;
    while(power > 0){
        if(power & 1) ans = ans * base % MOD;
        base = base * base % MOD;
        power >>= 1;
    }
    return ans;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    vector<ll> fac(1e6 + 5);
    fac[0] = 1ll;
    for(ll i=1;i<=1e6;i++){
        fac[i] = fac[i - 1] * i % MOD;
    }
    function<ll(ll, ll)> C = [&](ll n, ll m){
        if(n < m) return 0ll;
        return fac[n] * fastpow(fac[n - m], MOD - 2) % MOD * fastpow(fac[m], MOD - 2) % MOD;
    };
    int t;
    cin >> t;
    while(t--){
        ll n, m, k;
        cin >> n >> m >> k;
        ll ans = 0;
        if(n == m){
            cout << n * k % MOD << '\n';
            continue;
        }
        for(int i=1;i<=m;i++){
            ans += C(n - i - 1, m - i) * i % MOD * k % MOD * fastpow(fastpow(2ll, n - i), MOD - 2) % MOD;
            ans %= MOD;
        }
        cout << ans << '\n';
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Clarence Liu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值