Codeforces Round #529 (Div. 3) A~F题解

A. Repeating Cipher

  • 解题思路

    按距离间距索引字符即可。

  • 参考代码

#include<bits/stdc++.h>

using namespace std;

int n;
string s;
int main(){
    cin >> n >> s;
    int idx = 0,cnt = 1;
    while(idx < n){
        cout << s[idx];
        idx += cnt;
        cnt ++;
    }
    cout << endl;
    return 0;
}

B. Array Stabilization

  • 解题思路

    简单贪心,为了减小极差,要么删最大值要么删最小值。

  • 参考代码

#include<bits/stdc++.h>

using namespace std;

const int N = 2e5 + 10;
int n,a[N];
void solve(){
    sort(a + 1,a + 1 + n);
    //要么删最大值要么删最小值。
    printf("%d\n", min(a[n - 1] - a[1], a[n] - a[2]));
}
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; ++ i){
        scanf("%d", &a[i]);
    }
    solve();
    return 0;
}

C. Powers Of Two

  • 解题思路

    n n n按二进制位展开,那么展开后的每个二进制数都是 2 2 2的次幂。那么我们又知道对于 2 k , k > 0 2^k,k >0 2k,k>0,其可以转换成 2 2 2 2 k − 1 2^{k-1} 2k1,则会使个数加 1 1 1 根据此原理,我们从高往低凑成 k k k 2 2 2的次幂即可。

  • 参考代码

#include<bits/stdc++.h>

using namespace std;

int n,k;
int a[31];
void solve(){
    a[0] = 1;
    for(int i = 1; i < 31; ++ i){
        a[i] = a[i - 1] * 2;
    }
    //我们将n拆成二进制,那么二进制上的每一位都是2的次幂,而每一个不是1的2的次幂又可以拆分成2个2的次幂。通过这种思想去凑k。
    priority_queue<int> pos;
    for(int i = 0; i < 31; ++ i){
        if(n & a[i]){
            pos.push(i);
        }
    }
    //分解操作会使大小+1。如果可行那一定可以达到k。
    while(pos.size() < k && pos.top() > 0){
        int idx = pos.top();
        pos.pop();
        pos.push(idx - 1);
        pos.push(idx - 1);
    }
    if(pos.size() == k){
        cout << "YES" << endl;
        while(!pos.empty()){
            cout << a[(int)pos.top()] << " ";
            pos.pop();
        }
        cout << endl;
    }
    else{
        cout << "NO" << endl;
    }
}
int main(){
    cin >> n >> k;
    solve();
    return 0;
}

D. Circular Dance

  • 解题思路

    首先我们要知道,这实际上就是一个环,所以我们可以任取元素作为队头。而解决这道题目的关键就是确定一个元素的后两个元素的位置,那么可以根据后两个元素之间的关系来确定,因为第二个元素一定在第一个元素的后两个元素中。 这样循环迭代即可得出整个序列。

  • 参考代码

#include<bits/stdc++.h>
#define x first
#define y second

using namespace std;

const int N = 2e5 + 10;
int n;
pair<int,int> a[N];
void solve(){
    //注意,这个相当于一个圈,所以我们可以任取队头。
    //确定队头之后,怎么确定之后的两个元素的顺序呢。
    vector<int> q;//队列q。
    q.push_back(1);
    int x = a[1].x, y = a[1].y;
    bool flag = true;
    //判断x的后两个元素是不是y。
    if(a[x].x == y || a[x].y == y){
        flag = false;
    }
    if(flag){
        swap(x,y);//那么说明x的后一个元素不是y,则y在x前面,我们交换这两个值即可。保证x在前y在后。
    }
    q.push_back(x),q.push_back(y);
    int len = q.size();
    while(len < n){
        int cur = a[x].x;
        if(y == cur){
            //说明cur是第一个元素,而我们要将第二个元素入队。
            cur = a[x].y;
        }
        q.push_back(cur);
        //这样一直迭代后两个元素。
        len ++;
        x = y;
        y = cur;
    }
    for(int i = 0; i < len; ++ i){
        cout << q[i] << " ";
    }
    cout << endl;
}
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; ++ i){
        scanf("%d%d", &a[i].x, &a[i].y);
    }
    solve();
    return 0;
}

E. Almost Regular Bracket Sequence

  • 解题思路

    由于我们只能修改一个位置的括号,所以必然是只存在一对不合法的括号,我们将这个不合法的给找出来。再讨论情况。 那么我们可以利用栈来实现括号匹配,而当匹配完之后栈内必须要两个元素我们才可能实现。那么对于这其中的两个元素,我们需要判断是什么类型的,对于 ) ) )) )) ( ( (( ((我们都是可以是实现的,而 ) ( )( )(无论我们怎么修改都无法配对。

  • 参考代码

#include<bits/stdc++.h>

using namespace std;

int n;
string str;
void solve(){
    //由于我们只能修改一个位置的括号,所以必然是只存在一对不合法的括号,我们将这个不合法的给找出来。再讨论情况。
    stack<int> s;
    for(int i = 0; i < n; ++ i){
        if(str[i] == '('){
            s.push(i);
        }
        else{
            //碰到右括号就进行括号匹配。
            if(!s.empty() && str[s.top()] == '('){
                s.pop();
            }
            else{
                s.push(i);//如果不能匹配就入队。
            }
        }
    }
    //最后栈的大小一定是2个。其他的则不合法。
    int ans = 0;
    if(s.size() == 2){
        int idx2 = s.top();
        s.pop();
        int idx1 = s.top();
        //分析判断。注意按idx1 < idx2,因为我们是按下标顺序入栈的。
        if(str[idx1] == ')'){
            if(str[idx2] == '('){
                //)(当存在这种情况,我们无法修改使得其变为合法,因为进行操作只能对二者其中一个起作用。
                ans = 0;
            }
            else{
                //))当存在这种情况。我们将idx1左边的修改为(即可。
                for(int i = 0; i <= idx1; ++ i){
                    if(str[i] == ')'){
                        ans ++;
                    }
                }
            }
        }
        else{
            //说明是((类型,我们将)右边的修改为)即可。
            for(int i = idx2; i < n; ++ i){
                if(str[i] == '('){
                    ans ++;
                }
            }
        }
    }
    cout << ans << endl;
}
int main(){
    cin >> n >> str;
    solve();
    return 0;
}

F. Make It Connected

  • 解题思路

    最小生成树模板题。特别需要注意的一点就是我们不需要存储 n × ( n − 1 ) 2 \frac{n\times(n - 1)}{2} 2n×(n1)条边,根据贪心原则我们会选取权值较小的边构建 M S T MST MST,所以我们可以对顶点权排序,通过点权最小的点和其他点构建 n − 1 n-1 n1条边即可,剩下的即可舍去。既而我们再考虑增添的 m m m条边,将这些边组合排序进行Kruskal算法实现即可。

  • 参考代码

#include<bits/stdc++.h>

using namespace std;

const int N = 2e5 + 10;

typedef long long ll;

int n,m;
struct node{
    int u;
    ll w;
    bool operator < (const node &A){
        return w < A.w;
    }
}nodes[N];
struct edge{
    int u,v;
    ll w;
    bool operator < (const edge &A){
        return w < A.w;
    }
}edges[N << 2];
int tot,father[N];
int find(int x){
    int r = x;
    while(r != father[r])r = father[r];
    int i = x,j;
    while(father[i] != r){
        j = father[i];
        father[i] = r;
        i = j;
    }
    return r;
}
void solve(){
    sort(nodes + 1, nodes + 1 + n);
    for(int i = 2; i <= n; ++ i){
        //如果不适用魔法,而是直接连接的话必然是选择权值较小的,则以最小的与其他n-1个点相连即可。
        edges[++ tot].u = nodes[1].u;
        edges[tot].v = nodes[i].u;
        edges[tot].w = nodes[i].w + nodes[1].w;
    }
    sort(edges + 1, edges + 1 + tot);
    for(int i = 1; i <= n; ++ i)father[i] = i;
    ll ans = 0;
    for(int i = 1; i <= tot; ++ i){
        int fu = find(edges[i].u), fv = find(edges[i].v);
        if(n == 1)break;//当集合只剩一下即连通。
        if(fu != fv){
            father[fu] = fv;
            ans += edges[i].w;
            n --;
        }
    }
    printf("%lld\n", ans);
}
int main(){
    scanf("%d%d", &n ,&m);
    for(int i = 1; i <= n; ++ i){
        scanf("%lld", &nodes[i].w);
        nodes[i].u = i;
    }
    for(int i = 1; i <= m; ++ i){
        tot ++;
        scanf("%d%d%lld", &edges[tot].u, &edges[tot].v, &edges[tot].w);
    }
    solve();
    return 0;
}
posted @ 2022-03-26 16:48  unique_pursuit  阅读(41)  评论(0)    收藏  举报