AtCoder Beginner Contest 211 with Java その1

 こんにちは。

 昨日、初めてABCに参加しました。 これで自分も「プログラム、カイテマス」て言える気がして嬉しいです (業務ではExcelいじってばかりなので)。 「400点越えられたらいいな」と思い、目標はC問題まで完答としました。 準備はAtCoder Beginners Selectionを解いておきました。

 でもって結果は300点(A、B問題完答)でした。 B問題まではサクサク解いていったのですが、見事にC問題で躓きました。 力技でなんとかなるっしょ!とfor文をネストさせまくったのがダメでした。 というかそもそもC問題は、動的計画法を使って解く問題とのことでした。 「動的計画法…?」な自分。 解説動画を観て「そんな概念があるの?!頭良っ(あたまよっ)!」な自分。 …。 競プロに惹かれ始めているので、これからの週末が楽しみです。

A - Blood Pressure

提出したコードは以下の通りです。

import java.util.Scanner;

public class Main {
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int A = sc.nextInt();
        int B = sc.nextInt();
        double C = 0;
        
        C = (((double)A - (double)B) / 3) + (double)B;
        
        System.out.println(C);
    }
}

 「え、こんな簡単なの?!」が正直な感想でした。 その後、A問題はこれくらいの難度に設定されているらしいことを知りました。

 入力例2の注意書きにある通り、int型で計算すると小数が出ません。 そこで、自分はCを求めるときにdouble型にキャストしました。 初めからnextDouble()で入力を受け取れば、よりスッキリしたと思います。

B - Cycle Hit

提出したコードは以下の通りです。

import java.util.Scanner;

public class Main {
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String S1 = sc.nextLine();
        String S2 = sc.nextLine();
        String S3 = sc.nextLine();
        String S4 = sc.nextLine();
        
        String A = "H";
        String B = "HR";
        String C = "2B";
        String D = "3B";
        
        String ans = "No";
        
        int contain1 = 0;
        int contain2 = 0;
        int contain3 = 0;
        int contain4 = 0;
        
        if (A.matches(S1)||A.matches(S2)||A.matches(S3)||A.matches(S4)) 
            contain1 = 1;
        if (B.matches(S1)||B.matches(S2)||B.matches(S3)||B.matches(S4)) 
            contain2 = 1;
        if (C.matches(S1)||C.matches(S2)||C.matches(S3)||C.matches(S4)) 
            contain3 = 1;
        if (D.matches(S1)||D.matches(S2)||D.matches(S3)||D.matches(S4)) 
            contain4 = 1;
        
        if (contain1 == 1 && contain2 == 1 && contain3 == 1 && contain4 == 1) {
            ans = "Yes";
            System.out.println(ans);
        } else {
            System.out.println(ans);
        }
    }
}

 部分一致問題と捉えてしまったために時間をロスしました。 全文一致問題です。

 存在を判定したい文字列(H2B3BHR)が、与えられた文字列 S_iに含まれているかを一文字列ずつ判定しました。 含まれている場合にはフラッグ(contain1contain2contain3contain4)に1を格納します。 すべてのフラッグに1が格納されていれば、H2B3BHRが含まれていることになります。 最後にこのことを確認して、YesNoを出力しました。

 部分一致と捉えて何を誤ったかというと、matchesではなくcontainsを使ってしまいました。 そのため、HR S_iに含まれているとき、Hも含まれていると判定してしまいました。 これによって提出後にWAが出てしまい、解決に手間取りました。

 さて、この問題に対する公式解説動画ではもっとクールなやり方が提示されています。 以下は公式解説動画で提示された方法をJavaで実装した例です(C++での実装をJavaに焼き直したわけではないのでご注意下さい)。

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String[] string = new String[4];
        
        for (int i = 0; i < 4; i++) {
            string[i] = sc.next();
        }
        
        String[] strGiven = {"H", "2B", "3B", "HR"};
        int cnt = 0;
        
        //Arrays.sortメソッドを使ってソート
        Arrays.sort(string);
        Arrays.sort(strGiven);//2B, 3B, H, HR
        
        for (int i = 0; i < string.length; i++) {
            if (string[i].equals(strGiven[i])) {
                cnt++;
            }
        }
        
        if (cnt == 4) {
            System.out.println("Yes");
        } else {
            System.out.println("No");
        }
    }
}

こちらの方がコードがスッキリ(コード長:977 Byte → 673 Byte)していて自分は好きです。

C - chokudai

 こちらは別の記事に書くことにします。