Codeforces Round 923(Div.3) A~G

A.Make it White (模拟)

题意:

给一个字符串sss,找出最左边的BBB和最右边的BBB,以这两个字母为左右端点的区间包含有多少个字母。

分析:

按照要求,遍历一遍字符串找到左右端点即可。

代码:

#include <bits/stdc++.h>

using namespace std;

void solve() {
    int n;
    cin >> n;
    string s;
    cin >> s;
    int pos1 = 0, pos2 = n - 1;
    for (int i = 0; i < n; i++) {
        if (s[i] == 'B') {
            pos1 = i;
            break;
        }
    }
    for (int i = n; i >= 0; i--) {
        if (s[i] == 'B') {
            pos2 = i;
            break;
        }
    }
    cout << max(0, pos2 - pos1 + 1) << endl;
}

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

B.Following the String (贪心)

题意:

给出一个长度为nnn的数组aaaaia_iai表示j<ij < ij<isi=sjs_i=s_jsi=sj出现的个数。询问是否存在字符串sss符合这个数组。

分析:

枚举262626个字母,每次贪心地放入字母即可。

代码:

#include <bits/stdc++.h>

using namespace std;

void solve() {
    int n;
    cin >> n;
    string ans;
    vector<int> cnt(27, 0);
    for (int i = 0; i < n; i++) {
        int x;
        cin >> x;
        for (int j = 0; j < 26; j++) {
            if (cnt[j] == x) {
                ++cnt[j];
                ans += char('a' + j);
                break;
            }
        }
    }
    cout << ans << endl;
}

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

C. Choose the Different Ones! (贪心)

题意:

给一个长度为nnn的数组aaa,一个长度为mmm的数组bbb,和一个偶数kkk,询问能否从两个数组各取出k/2k/2k/2个数字,组成一个1−k1-k1k的排列。

分析:

对于1−k1-k1k的数字,如果只在a,ba,ba,b中的一个数组中出现,那么就必须取,计算拿完这样的元素需要多少次,是否满足两个数组拿取的次数都满足小于等于k/2k/2k/2,其余元素随便取即可。

代码:

#include <bits/stdc++.h>

using namespace std;
map<int, int> map1, map2;

void solve() {
    int n, m, k, x;
    map1.clear();
    map2.clear();
    cin >> n >> m >> k;
    int cnt1 = k / 2, cnt2 = k / 2;
    for (int i = 1; i <= n; i++) {
        cin >> x;
        map1[x]++;
    }
    for (int i = 1; i <= m; i++) {
        cin >> x;
        map2[x]++;
    }
    int flag = 0;
    for (int i = 1; i <= k; i++) {
        if (!map1.count(i) && !map2.count(i)) {
            flag = 1;
            break;
        } else if (map1.count(i) && !map2.count(i)) {
            cnt1--;
        } else if (map2.count(i) && !map1.count(i)) {
            cnt2--;
        }
    }
    if (cnt1 < 0 || cnt2 < 0 || flag)
        cout << "NO" << endl;
    else
        cout << "YES" << endl;
}

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

D.Find the Different Ones! (思维)

题意:

给一个长度为nnn的数组aaammm次询问,每次询问给出一个区间[l,r][l,r][l,r],询问是否有i,ji,ji,j满足以下条件:

  • l≤i,j≤r,ai≠ajl \le i,j\le r,a_i \neq a_jli,jr,ai=aj

如果存在输出i,ji,ji,j

分析:

left[i]left[i]left[i]维护iii左边第一个和自己不同的元素,每次询问判断是否left[r]<lleft[r] < lleft[r]<l 即可。

代码:

#include <bits/stdc++.h>

using namespace std;
const int MAXN = 2e5 + 5;
int a[MAXN], left1[MAXN];

void solve() {
    int n, q, l, r;
    cin >> n;
    left1[1] = 0;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    for (int i = 2; i <= n; i++) {
        if (a[i] != a[i - 1])
            left1[i] = i - 1;
        else
            left1[i] = left1[i - 1];
    }
    cin >> q;
    for (int i = 1; i <= q; i++) {
        cin >> l >> r;
        if (left1[r] < l)
            cout << -1 << " " << -1 << endl;
        else
            cout << left1[r] << " " << r << endl;
    }
    cout << endl;
}

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

E.Klever Permutation (思维)

题意:

给定两个整数n,kn,kn,k,询问是否存在满足以下条件的合法排列:

  • 对所有满足i+k−1≤ni+k-1 \le ni+k1niii,每个区间[i−i+k−1][i-i+k-1][ii+k1]的和中的最大值和最小值相差不超过111

分析:

设每个区间的和为s[i]s[i]s[i],那么需要构造成$s[i]-s[i-1]=1,s[i]-s[i]=-1 $交替这种形式。设前444个元素为a,b,c,da,b,c,da,b,c,d,那么可以想到如下构造:[a,b,c,d,a+1,b−1,c+1,d−1,a+2,b−2,c+2,d−2...][a,b,c,d,a+1,b-1,c+1,d-1,a+2,b-2,c+2,d-2...][a,b,c,d,a+1,b1,c+1,d1,a+2,b2,c+2,d2...]即可。

代码:

#include <bits/stdc++.h>

using namespace std;
const int MAXN = 2e5 + 5;
int ans[MAXN];

void solve() {
    int n, k;
    cin >> n >> k;
    int flag1 = 1, num = 1, now = 1;
    while (now <= k) {
        if (flag1) {
            for (int i = now; i <= n; i += k) {
                ans[i] = num;
                ++num;
            }
        } else {
            for (int i = now + ((n - now) / k) * k; i >= 1; i -= k) {
                ans[i] = num;
                ++num;
            }
        }
        flag1 ^= 1;
        ++now;
    }
    for (int i = 1; i <= n; i++)
        cout << ans[i] << " ";
    cout << endl;
}

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

F.Microcycle (图论)

题意:

给出一张nnn个点,mmm条边的无向简单图,图不一定联通,在其中寻找包含最小边的环,输出最小边的边权和环上的所有节点。

分析:

从小到大枚举边权,用并查集判断两个点是否在一个集合内,如果在,证明找到了在环内的最小边,从这两个点中任选一点出发开始bfsbfsbfs,搜索并记录路径即可。

代码:

#include <bits/stdc++.h>

using namespace std;
const int MAXN = 5e5 + 5;
vector<int> g[MAXN];

struct Node {
    int w, u, v;

    friend bool operator<(const Node &a, const Node &b) {
        if (a.w != b.w)
            return a.w > b.w;
        return a.u < b.u;
    }
} edge[MAXN];

int fa[MAXN];

int get(int x) {
    if (fa[x] != x)
        fa[x] = get(fa[x]);
    return fa[x];
}

void solve() {
    int n, m;
    vector<int> ans;
    queue<int> q;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        g[i].clear();
    for (int i = 1; i <= n; i++)
        fa[i] = i;
    for (int i = 1; i <= m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        edge[i] = {w, u, v};
        g[u].push_back(v);
        g[v].push_back(u);
    }
    sort(edge + 1, edge + m + 1);
    int a, b, tmp = 1e9;
    for (int i = 1; i <= m; i++) {
        auto [w, u, v] = edge[i];
        int tmp1 = get(fa[u]);
        int tmp2 = get(fa[v]);
        if (tmp1 == tmp2 && w < tmp) {
            a = u, b = v;
            tmp = w;
        }
        fa[tmp1] = tmp2;
    }
    q.push(a);
    vector<int> Depth(n + 1, 0);
    while (q.size()) {
        auto u = q.front();
        q.pop();
        for (auto v: g[u]) {
            if (Depth[v])
                continue;
            if (u == a && v == b)
                continue;
            if (v == a)
                continue;
            Depth[v] = Depth[u] + 1;
            q.push(v);
        }
    }
    int dep = Depth[b], fr = b;
    while (dep) {
        ans.push_back(fr);
        for (auto v: g[fr]) {
            if (Depth[v] == dep - 1) {
                dep--;
                fr = v;
                break;
            }
        }
    }
    ans.push_back(a);
    cout << tmp << " " << ans.size() << endl;
    for (auto v: ans)
        cout << v << " ";
    cout << endl;
}

int main() {
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}

G.Paint Charges (dp)

题意:

给定nnn个格子,aia_iai表示这个格子可以使用的颜料数量。每次操作可以选定一个格子,并选择将[max(i−ai+1,1),i][max(i-a_i+1,1),i][max(iai+1,1),i]或者[i,min(i+ai−1,n)][i,min(i+a_i-1,n)][i,min(i+ai1,n)]的格子涂色,每个格子可以被涂色多次,询问将[1,n][1,n][1,n]所有格子都涂上颜色的最少操作次数。

分析:

dp[i][j][k]dp[i][j][k]dp[i][j][k]表示当使用前iii个元素,最左侧未填充位置是jjj ,最右侧已填充位置是kkk,所需要的最小操作数。有以下三种情况:

  • 不进行操作的状态转移:dp[i][j][k]=min(dp[i][j][k],dp[i−1][j][k]);dp[i][j][k]=min(dp[i][j][k],dp[i-1][j][k]);dp[i][j][k]=min(dp[i][j][k],dp[i1][j][k]);
  • 向左填充的状态转移,需要根据i,j,k,li,j,k,li,j,k,l大小进行讨论。

  • 向右填充的状态转移,需要根据i,j,k,ri,j,k,ri,j,k,r大小进行讨论。

代码:

#include <bits/stdc++.h>

using namespace std;
const int INF = 0x3f3f3f3f;
int a[105];
int dp[105][105][105];

void solve() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 0; i <= n; i++) {
        for (int j = 1; j <= n + 1; j++) {
            for (int k = 0; k <= n; k++) {
                dp[i][j][k] = INF;
            }
        }
    }
    dp[0][1][0] = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n + 1; j++) {
            for (int k = 0; k <= n; k++) {
                dp[i][j][k] = min(dp[i][j][k], dp[i - 1][j][k]);
                int l = max(i - a[i] + 1, 1);
                if (l <= j) {
                    int tmp1 = max(i, k);
                    dp[i][tmp1 + 1][tmp1] = min(dp[i][tmp1 + 1][tmp1], dp[i - 1][j][k] + 1);
                }
                int r = min(i + a[i] - 1, n);
                if (j < i) {
                    dp[i][j][max(k, r)] = min(dp[i][j][max(k, r)], dp[i - 1][j][k] + 1);
                } else {
                    int tmp1 = max(k, r);
                    dp[i][tmp1 + 1][tmp1] = min(dp[i][tmp1 + 1][tmp1], dp[i - 1][j][k] + 1);
                }
            }
        }
    }
    cout << dp[n][n + 1][n] << endl;
}

int main() {
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}

赛后交流

在比赛结束后,会在交流群中给出比赛题解,同学们可以在赛后查看题解进行补题。

群号: 704572101,赛后大家可以一起交流做题思路,分享做题技巧,欢迎大家的加入。

### 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; } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值