AtCoder Beginner Contest029(ABC029) 解説

ABC
ぬるから
ぬるから

いきなりのAtcoderが出てきましたが、このブログのメインコンテンツ(予定)です。
その内、Atcoderの自体の説明記事を書きます。


注意

・言語はC++で記入します。
・マクロは使っていませんが、

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

 この二つだけは書いています。
・説明雑で、ソース汚いです(コメントアウトされたデバッグ出力も残っています)。

A – 複数形

A - 複数形
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.

入力の末尾にsを付ける問題。
言語によって様々かと思いますが、C++は“+”演算子で文字列の結合ができます。
入力の文字列に”+”で”s”を結合し、出力すればOKです。

#include<bits/stdc++.h>

using namespace std;

int main(){
    string s;
    cin>>s;
    cout<<s+"s"<<endl;
}

B – カキ

B - カキ
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.

12個の文字列の中から”r”が含まれている文字列の数を出力する問題。
C++はfind関数を使うことで、文字の探索ができるため、それでOKです。
find関数は、探索文字が存在する場合は最初の出現位置が、存在しない場合はstring::nposが返ってきます。そのため、string::nposではない個数を数えることで”r”が含まれる文字列の個数が分かります

#include<bits/stdc++.h>

using namespace std;

int main(){
    int ans=0;
    for(int i=0;i<12;i++){
        string s;
        cin>>s;
        //cout<<s.find('r')<<endl;
        if(s.find('r')!=string::npos){
            ans++;
        }
    }
    cout<<ans<<endl;
}

C – Brute-force Attack

C - Brute-force Attack
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.

‘a’,’b’,’c’から作れる、長さNの文字列全てを辞書順で出力する問題。
N桁3進数を考えれば上手くいきます。(3進数の0を’a’,1を’b’,2を’c’みたいに置き換えて考える)
Nが最大の8のときでも、3^8=6561通りしかないので、時間的な余裕はかなりあります。

具体的には、
i=0~3^N-1回のforを回す
 iを3進数に直す。
 3進数の0~2をそれぞれ’a’,’b’,’c’に置き換えて出力する。

辞書順に出力という条件があるため、そこにだけ注意です。

#include<bits/stdc++.h>

using namespace std;

int main(){
    int N;
    cin>>N;
    for(int i=0;i<pow(3,N);i++){
        int n=i;
        int c=N;
        string s="";
        while(c--){
            s=(char)('a'+n%3)+s;
            n/=3;
        }
        cout<<s<<endl;
    }
}

D – 1

D - 1
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.

1~Nの数字を書いたとき、’1’は何回書くことになるか。
愚直に考えれば、各数字に1が幾つ含まれているか調べる方法かと思います。

#include<bits/stdc++.h>

using namespace std;

int main(){
    int N;
    cin>>N;
    int ans=0;

    for(int i=1;i<=N;i++){
        int n=i;
        while(n!=0){
            if(n%10==1) ans++;
            n/=10;
        }
    }
    cout<<ans<<endl;
}

このコードはO(NlogN(底=10))になるため、N=10^9の時は計算量が9*10^9になってTLEします。
部分点は満たしているため20点解法となります。

※満点を取るためには?
桁DPします。桁DPの細かいやり方は調べてください。
dp[上位i桁目][好きな数字が置けるか][‘1’の個数]
として、DPテーブルを更新していきます。
O(logN(底=10))になるため(正確には定数倍*400がある)、余裕をもってACがとれます。

#include<bits/stdc++.h>

using namespace std;

int main(){
    string N;
    cin>>N;

    int dp[20][2][20]={{{0}}};

    dp[0][0][0]=1;
    for(int i=0;i<(int)N.size();i++){
        int n=N[i]-'0';
        for(int j=0;j<2;j++){
            for(int k=0;k<20;k++){
                int nx=9;
                if(j==0) nx=n;
                for(int l=0;l<=nx;l++){
                    int jx=0;
                    int kx=0;
                    if(j==1||l<n) jx=1;
                    if(l==1) kx=1;
                    dp[i+1][jx][kx+k]+=dp[i][j][k];
                }
            }
        }
        //cout<<dp[i+1][0][0]<<","<<dp[i+1][0][1]<<"+"<<dp[i+1][1][0]<<","<<dp[i+1][1][1]<<endl;
    }
    int ans=0;
    for(int i=0;i<20;i++){
        //cout<<dp[N.size()][0][i]<<","<<dp[N.size()][1][i]<<endl;
        ans+=(dp[N.size()][0][i]+dp[N.size()][1][i])*i;
    }
    cout<<ans<<endl;
}

おわりの一言

ぬるから
ぬるから

桁DP、とても苦手です。
キレイに書ける方、毎回すごいなって思います。

コメント

タイトルとURLをコピーしました