0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ABC391個人的備忘録

Posted at

撒いたエラーすら読んじゃいない男の備忘録です

コンテスト概要

AtCoder Beginner Contest 391

開催日:2025年2月1日 21:00-22:40

A-Lucky Direction

考察

方角の反対側を出力する。南西の反対は北東であり、それぞれ「南」と「北」、「西」と「東」を入れ替えるだけでよい。
ここまで単純な考察になると考慮漏れがないか不安になる。

提出

A.cpp
#include <bits/stdc++.h>
using namespace std;

int main(){
    map<char,char>mp;
    //逆の方角の準備
    mp['N'] = 'S',mp['S'] = 'N';
    mp['E'] = 'W',mp['W'] = 'E';

    string s;
    cin >> s;

    for(auto x:s) cout << mp[x];
    cout << endl;
}

B - Seek Grid

考察

言われた通りにやるとしか言いようがない。aとbの範囲に気を付けながら全探査。
a,bの値が教えられていることに優しさを感じる。

提出

B.cpp
#include <bits/stdc++.h>
using namespace std;

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

    vector<vector<char>>s (n,vector<char>(n)),t (m,vector<char>(m));
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++) cin >> s[i][j];
    }

    for(int i=0;i<m;i++){
        for(int j=0;j<m;j++) cin >> t[i][j];
    }

    //左上の座標を全探査していく
    for(int a=0;a<=n-m;a++){
        for(int b=0;b<=n-m;b++){
            bool che = true;
            for(int i=0;i<m;i++){
                for(int j=0;j<m;j++){
                    if(s[a+i][b+j] != t[i][j]) che = false;
                }
            }

            if(che) cout << a+1 << " " << b+1 << endl;
        }
    }
    
}

C - Pigeonhole Query

考察

それぞれの鳩の現住所と巣にいる鳩の数を管理する配列を用意する。
クエリ1ごとに鳩Pの住所を書き換え、鳩の匹数も変える。この時書き換えるべき巣は前住所と現住所だけ。
複数匹いる巣の数を管理する変数を用意し、前住所が2匹から1匹になったらマイナス、現住所が1匹から2匹になったらプラスをする。
クエリ2のタイミングで変数を出力するだけでOK。

提出

C.cpp
#include <bits/stdc++.h>
using namespace std;

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

    //巣にいる鳩の数
    vector<int>num (n,1);
    //鳩の住所録
    vector<int>pos (n);
    for(int i=0;i<n;i++) pos[i] = i;

    int ans = 0;
    for(int i=0;i<q;i++){
        int x;
        cin >> x;

        if(x == 1){
            int x,y;
            cin >> x >> y;
            x--,y--;
            
            //鳩を移動させる
            num[pos[x]]--,num[y]++;
            //古巣が単体になったら答えを減らす
            if(num[pos[x]] == 1) ans--;
            //新居が複数になったら答えを増やす
            if(num[y] == 2) ans++;

            pos[x] = y;
        }else{
            cout << ans << endl;
        }

    }    
}

D - Gravity

考察

1秒ごとに進めるとyが10億の高さにあるとき当然TLEなのでうまく盤面を圧縮する必要がある。
ここでそれぞれのxの位置において一番手前にあるブロックが落ち切ったときにブロックが消える。(一列埋まる前提)
つまりは一列が消えるタイミングはそれぞれのxで一番落ちてくるのが遅いブロックに依存する。その時間がわかれば高速にブロックが消えるタイミングがわかる。
タイミングを求めてしまえば時刻TはブロックAが消えるより後か前かを答えるだけ。

提出

D.cpp
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

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

    
    vector<vector<pair<int,int>>>num (w,vector<pair<int,int>>(0));
    for(int i=0;i<n;i++){
        int x,y;
        cin >> x >> y;
        x--;

        //それぞれのx座標のブロックがどの位置にあるかを格納
        num[x].push_back({y,i});
    }

    //最大で何列消えるかをチェック
    //一番下まで消えずに残ったとして一番低いブロック以下はすべて消える。
    int siz = (1<<30);
    for(auto x:num){
        sort(x.begin(),x.end());
        int s = x.size(); 
        siz = min(siz,s);
    }

  //いったん答えに大きな値を入れておく(無限=消えない)
    int lim = (1<<30);
    vector<int> ans (n,lim);
    int now = 0;

    for(int i=0;i<siz;i++){
        for(int j=0;j<w;j++){
            now = max(now,num[j][i].first);
        }
        for(int j=0;j<w;j++){
            ans[num[j][i].second] = now;
        }
        now++;
    }


    int q;
    cin >> q;
    for(int i=0;i<q;i++){
        int x,y;
        cin >> x >> y;
        y--;

        //ブロックが消えるのはyより前か後か
        if(x < ans[y]) cout << "Yes" << endl;
        else cout << "No" << endl;

    }
    
}

E - Hierarchical Majority Vote

考察

それぞれ3つの組について3つが同じなら2つ、2つだけ同じなら1つ変更させる必要がある。それを踏まえすべての数に現在の値と変更のためのコストを持たせる。
$3^N$個を$3^{N-1}$に減らすとき、3つが同じなら2つのコストの合計が小さいものを、2つが同じならそのうちコストの小さいものをメモしておく。
これを繰り返せばセグ木チックにコストを確認できる。

しかし結果はWA。20分格闘しなんとなくエラーコードを見ると添え字ミスが発覚。
20分を嘆き1文字変更するだけでAC。

提出

E.cpp
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

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

    queue<pair<int,int>> que;
    int siz = pow(3,n);
    for(int i=0;i<siz;i++){
        char x;
        cin >> x;
        //最初変更のコストは当然1
        que.push({x-'0',1});
    }

    //初期の配列が1つだけになるまで
    while(que.size() != 1){
        vector<pair<int,int>>num (3);
        int sum = 0;
        for(int i=0;i<3;i++){
            num[i] = que.front();
            sum += num[i].second;
            que.pop();
        }

        pair<int,int>ans;
        //3つ同じか、2つ同じかで場合分け
        if(num[0].first == num[1].first && num[1].first == num[2].first){
            ans.first = num[0].first;
            //コストのうち小さいほう二つの合計が併合後のコスト
            ans.second = sum - max({num[0].second,num[1].second,num[2].second});
        }else{
            if(num[0].first != num[1].first) ans.first = num[2].first;
            else ans.first = num[0].first;
            ans.second = (1<<30);
            //2つある文字のうちコストが小さいものが併合後のコスト
            for(int i=0;i<3;i++){
                if(ans.first == num[i].first) ans.second = min(ans.second,num[i].second);
            }
        }

        //併合した値をqueに
        que.push(ans);
    }

    cout << que.front().second << endl;    
}

F - K-th Largest Triplet

考察

ABC331_E問題の変数が1つ増えたような問題。なので何とか剽窃できないかと解説を見るが上手くいかずTIME UP。
もっと素直でよかったのか。

結果

ABCDE(2) 5完 95:14

順位 1731位
パフォーマンス 1278

感想

エラーコードはしっかり確認するべきだったそうすれば500位くらいは順位が上がっていた。
入水はまだ遠い。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?