LoginSignup
0
0

【ABC352】AtCoder Beginner Contest 352【C++】

Posted at

コンテスト名

AtCoder Beginner Contest 352

コンテストURL

開催日

2024/05/04 21:00-22:40


A: AtCoder Line

解法

  • 駅 $Z$ が駅 $X$ と駅 $Y$ の間にあるかを判別する
ABC352A.cpp
#include <iostream>
using namespace std;

int main(){
    int n, x, y, z;
    cin >> n >> x >> y >> z;

    if(x>y && x>z && z>y){
        cout << "Yes" << endl;
    }else if(x<y && x<z && z<y){
        cout << "Yes" << endl;
    }else{
        cout << "No" << endl;
    }

    return 0;
}

B: Typing

解法

  • 前から順番に比較する
ABC352B.cpp
#include <iostream>
#include <string>
using namespace std;

int main(){
    string s, t;
    cin >> s >> t;

    int j = 0;
    for(int i=0; i<s.size(); i++){
        while(s[i]!=t[j]){
            j++;
        }
        if(i){
            cout << " ";
        }
        cout << j+1;
        j++;
    }

    cout << endl;
    return 0;
}

C: Standing On The Shoulders

解法

  • どの巨人が一番上に立つと高さが最大になるかについて $O(N)$ の全探索をする
  • 一番上に立つ巨人以外は肩の高さ $A_i$ 分だけ貢献する
  • 一番上に立つ巨人は頭の高さ $B_i$ 分だけ貢献する
  • $A_i$ の総和を求めて $B_i - A_i$ の最大値を足す
  • 「巨人の肩の上に立つ」
ABC352C.cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main(){
    int n;
    cin >> n;

    vector<int> A(n), B(n);
    for(int i=0; i<n; i++){
        cin >> A[i] >> B[i];
    }

    long long int sum = 0;
    for(int i=0; i<n; i++){
        sum += A[i];
    }

    long long int maxv = 0;
    for(int i=0; i<n; i++){
        maxv = max(maxv, sum-A[i]+B[i]);
    }

    cout << maxv << endl;
    return 0;
}

D: Permutation Subsequence

解法

  • どの連続する $K$ 個の数列を採用するかを全探索する
    • 連続する $K$ 個の数列は $N - K + 1$ 通り
  • 数列が昇順になるように添字列を並び替える
  • set<int> を用いて添字の最大値と最小値を更新する
    • erase()insert() で更新する
      • 計算量はともに $O(\log N)$
    • 最大値は *.rbegin() 、最小値は *.begin() によって $O(1)$ で取得できる
  • 最大値と最小値の差 $i_K - i_1$ の最小値を求める
ABC352D.cpp
#include <iostream>
#include <vector>
#include <set>
using namespace std;

int main(){
    int n, k;
    cin >> n >> k;

    vector<int> P(n);
    int p;
    for(int i=0; i<n; i++){
        cin >> p;
        p--;
        P[p] = i;
    }

    set<int> S;
    for(int i=0; i<k; i++){
        S.insert(P[i]);
    }

    int ans = *S.rbegin() - *S.begin();

    for(int i=k; i<n; i++){
        S.erase(P[i-k]);
        S.insert(P[i]);
        ans = min(ans, *S.rbegin() - *S.begin());
    }

    cout << ans << endl;
    return 0;
}

E: Clique Connect

解法

  • クラスカル法で最小全域木を求める
  • 部分集合 $S_i = \lbrace A_{i, 1}, A_{i, 2},..., A_{i, K_i}, \rbrace$ のすべての頂点間に重み $C_i$ の辺を追加することは、すべての $A_{i, j}, A_{i, j+1}$ 間だけに重み $C_i$ の辺を追加することと同じ
    • 辺の数を $\frac{K_i (K_i - 1)}{2}$ 本から $K_i - 1$ 本に省略できる
  • クラスカル法において、すでにすべての頂点が連結であるならばそれ以上は辺が追加されないという性質を利用する
ABC352E.cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <tuple>
using namespace std;

struct UnionFind{
    vector<int> P;
    vector<int> S;

    UnionFind(int n) : P(n), S(n, 1){
        for(int i=0; i<n; i++){
            P[i] = i;
        }
    }

    int find(int x){
        if(x==P[x]){
            return x;
        }
        return P[x] = find(P[x]);
    }

    void unite(int x, int y) {
        x = find(x);
        y = find(y);

        if(x==y){
            return;
        }

        if(S[x]<S[y]){
            swap(x, y);
        }

        P[y] = x;
        S[x] += S[y];
    }

    bool same(int x, int y) {
        return find(x) == find(y);
    }

    int size(int x) {
        return S[find(x)];
    }
};

int main(){
    int n, m;
    cin >> n >> m;

    vector<tuple<int, int, int>> V;
    int k, c;
    for(int i=0; i<m; i++){
        cin >> k >> c;
        int pre, a;
        for(int j=0; j<k; j++){
            cin >> a;
            a--;
            if(j){
                V.emplace_back(c, pre, a);
            }
            pre = a;
        }
    }

    sort(V.begin(), V.end());
    UnionFind uf(n);
    long long int sum = 0;
    for(int i=0; i<V.size(); i++){
        auto [c, a, b] = V[i];
        if(!uf.same(a, b)){
            sum += c;
            uf.unite(a, b);
        }
    }

    if(uf.size(0)!=n){
        cout << -1 << endl;
    }else{
        cout << sum << endl;
    }

    return 0;
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0