taiPyのお悩み解決ブログ

日々の発見をまとめます!

(編集中)学習記録:Java:C - Airport Code , AtCoder Beginner Contest 349

問題と解説へのリンク

問題 C - Airport Code https://atcoder.jp/contests/abc349/tasks/abc349_c

解説へのリンク

問題のポイントとメモ

  • 正規表現でも求めることが出来る!
  • T の最後の文字が X でない場合, T が S の部分列であるかどうか判定すればよいです.T の最後の文字が X である場合, T の最初の2文字が S の部分列であるかどうか判定すればよいです.

解答例

import java.util.Scanner;

public class Main {
    public static boolean check(String S, String T) {
        int i = 0;
        for (char t : T.toCharArray()) {
            while (i < S.length() && S.charAt(i) != t) {
                i++;
            }
            if (i == S.length()) {
                return false;
            }
            i++;
        }
        return true;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String S = scanner.nextLine().toUpperCase();
        String T = scanner.nextLine();
        scanner.close();

        System.out.println(check(S, T.charAt(T.length() - 1) != 'X' ? T : T.substring(0, T.length() - 1)) ? "Yes" : "No");
    }
}

正規表現バージョン

ChatGPTに変換してもらったがTLEだった。うん。他のコードを参考にするか?C++など。




    
    
  

学習記録:Java:B - Commencement , AtCoder Beginner Contest 349

問題と公式の解答へのリンク

問題 B - Commencement https://atcoder.jp/contests/abc349/tasks/abc349_b

公式の解答へのリンク https://atcoder.jp/contests/abc349/editorial/9778

解答例 自分の

Javaの解答例(自作)

Point

  • 文字が何文字出てきてますかー
  • 1回の繰り返しの文字の種類は、、2回の繰り返しの文字の種類は、、って100回の繰り返しの文字の種類は?ってforループさせます。
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        int sLength = s.length();

        Map<Character, Integer> map = new HashMap<>();

        for (int i = 0; i < sLength; i++) {
            map.put(s.charAt(i), map.getOrDefault(s.charAt(i), 0) + 1);
        }


        for (int i = 1; i <= 101; i++) {
            int count = 0;
            for (Integer num : map.values()) {
                if (num == i) {
                    count ++;
                }
            }

            if (! (count == 0 || count == 2)) {
                System.out.println("No");
                return;
            }
            
        }

        System.out.println("Yes");

        sc.close();
    }
}

公式の解答(Python)をJavaに変換

公式の解答(Python)をJavaに変換

Point

  • アルファベットは26文字
  • char型の'a'は97、'b'は98というように、char型のアルファベットの持つ数値は連続している。

アルファベットを出力するコード

        char c = 'a';
        for (int i = 0; i < 26; i++) {
            System.out.println(c++);
        }

解答例

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String S = scanner.nextLine();
        int[] cnt = new int[26];
// 文字が出てきたら数えている
// 配列のindex=0が1文字目、つまりaを意味している。
        for (char c : S.toCharArray()) {
            cnt[c - 'a']++;
        }

// 1文字連続、2文字連続・・・100文字連続が何種類あるかを数える
        int[] cnt2 = new int[101];
        for (int c : cnt) {
            if (c > 0) {
                cnt2[c]++;
            }
        }

// 判定
        boolean isAllZeroOrTwo = true;
        for (int c : cnt2) {
            if (c != 0 && c != 2) {
                isAllZeroOrTwo = false;
                break;
            }
        }
        System.out.println(isAllZeroOrTwo ? "Yes" : "No");
    }
}

学習記録:Java:A31 - Divisors , 競技プログラミングの鉄則 演習問題集

はじめに

競技プログラミングの鉄則 演習問題集 の A31 - Divisors を解いたので、その備忘録を!

ポイントとミスったポイント

ポイント

  • 包除原理を使う。高校数学で学ぶ集合的なイメージ。重なり合っている部分は重複して数えちゃうから引こうね!ってこと!
  • 3の倍数が何個あるか?という問題だから、普通に3で割った数が3の倍数の個数だよね。
  • 5の倍数も3の倍数と一緒。

ミスったポイント

  • 数え上げちゃった。計算量がバカでかい。O(3N)
    • 正解は4回計算するだけで行けちゃう。
  • long使っていない。intじゃ、小さすぎて正しく表示できないよ。

目次

問題と公式の解答

A31 - Divisors https://atcoder.jp/contests/tessoku-book/tasks/tessoku_book_ae

公式の解答へのリンク https://github.com/E869120/kyopro-tessoku/blob/main/codes/java/chap05/answer_A31.java

解答例

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        long n = sc.nextLong();

        // 数える用の変数を用意するよー
        // 正直用意しなくてもいいよ。公式見てみて。すっきりしている。
        long threeCnt = 0, fiveCnt = 0, fifteenCnt = 0;

        threeCnt = n / 3;
        fiveCnt = n / 5;
        fifteenCnt = n / (5 * 3);


        System.out.println(threeCnt + fiveCnt - fifteenCnt);
        sc.close();
    }
}

誤った回答例(TLE)

時間超過しちゃうよー。計算量がバカでかいからねー。

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        long n = sc.nextLong();

        // 数える用の変数を用意するよー
        int threeCnt = 0, fiveCnt = 0, fifteenCnt = 0;

        for (int i = 1; i <= n; i++) {
            if (i % 3 == 0) {
                threeCnt ++;
            }

            if (i % 5 == 0) {
                fiveCnt ++;
            }

            if (i % (3 * 5) == 0) {
                fifteenCnt ++;
            }
        }

        System.out.println(threeCnt + fiveCnt - fifteenCnt);
        sc.close();
    }
}

学習記録:Java:A29 - Power , 競技プログラミングの鉄則 演習問題集

はじめに

Javaで解答例を書いています。自分用のメモです。問題としては、競技プログラミングの鉄則 演習問題集 の A29 - Power という問題です!○○乗を素早く計算するアルゴリズムが使われています!あとは、割り算の余りの性質を使っていますね。

問題のポイントと自分がミスったポイント

問題のポイント

  • ○○乗って分解できますよね。5乗なら1乗と4乗に。高校の時に習った指数法則。

ミスしたポイント

  • if ((b / wari) % 2 == 1)の意味が分からなかった。2のi乗の時に、二進数に直したときに1になっているポイントでanswerに2のi乗を掛け合わせるために用意していたんだなー。

目次

問題と公式の解答例

問題 A29 - Power

A29 - Power , https://atcoder.jp/contests/tessoku-book/tasks/math_and_algorithm_aq

公式の解答例

https://github.com/E869120/kyopro-tessoku/blob/main/codes/java/chap05/answer_A29.java

解答例

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        long a = sc.nextLong();
        long b = sc.nextLong();

        System.out.println(Power(a, b, 1000000007));
    }

    static long Power(long a, long b, long m) {

        long p = a;
        long answer = 1;
// n が 30 未満なのは問題の制約から
// 制約に応じて変える必要アリ
        for (int i = 0; i < 30; i++) {
// 計算を2進数で考えよう
            int wari = (1 << i);
// bを2進数で表したとき、1になっているところでpをかけるよ
            if ((b / wari) % 2 == 1) {
                answer = (answer * p) % m;
            }
// pのi乗を計算
            p = (p * p) % m;
        }

        return answer;
    }
}

学習記録:B28 - Fibonacci Easy (mod 1000000007) , 競技プログラミングの鉄則 演習問題集

はじめに

競技プログラミングの鉄則 演習問題集 の B28 - Fibonacci Easy (mod 1000000007) を解きました!いやー、余りの性質に関していい考察といいますか、トレーニングになりました。

この問題のポイント

  • 余りを出すことがポイント
  • nが9乗くらいあるので、フィボナッチ数列を出すことがまず困難
  • でも、余りって計算するどのタイミングでとっても余りって同じになるんですよね。

参考文献

「998244353 で割ったあまり」の求め方を総特集! 〜 逆元から離散対数まで 〜 , https://qiita.com/drken/items/3b4fdf0a78e7a138cd9a

目次

問題と公式解説

問題 B28 - Fibonacci Easy (mod 1000000007)

https://atcoder.jp/contests/tessoku-book/tasks/math_and_algorithm_ap

B28 - Fibonacci Easy (mod 1000000007) , 競技プログラミングの鉄則 演習問題集

公式解説

https://github.com/E869120/kyopro-tessoku

解答例(自作)

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        long n = sc.nextInt();

        List<Long> list = new ArrayList<Long>();
        
        long ans = 0;
        long tempTwo = 0;
        long tempOne = 0;
        long value = 1000000007;

        for (int i = 0; i < n; i++) {

            if (i == 0) {
                tempTwo = 1;
            }
            if (i == 1) {
                tempOne = 1;
            }

            ans = tempTwo + tempOne;
            ans %= value;
            tempTwo = tempOne;
            tempOne = ans;
        }

        System.out.println(ans);    
    }

}

解答例(公式をJavaに変換)

上記の例との違いは、配列を使っているか使っていないか。上記の自作解答例は配列を使わないバージョン。対して、公式のは配列を使うバージョン。どっちがいいとかじゃないとは思うけれども。公式の方がすっきりしているので、公式の方で自由自在に書けるようになりたい!

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int mod = 1000000007;

// +9はテキトーに。まあ、溢れないようにするため。index out of.. のエラーが出ないように。
        int[] a = new int[n + 9];

// 代入
        a[1] = 1;
        a[2] = 1;

        for (int i = 3; i <= n; i++) {
// 余りを計算しちゃって格納しちゃう!
            a[i] = (a[i - 2] + a[i - 1]) % mod;
        }

        System.out.println(a[n]);
    }

}

Javaの解答例:学習記録:A28 - Blackboard , 競技プログラミングの鉄則 演習問題集

はじめに

競技プログラミングの鉄則を読み進めているので、自分で解いた記録を残します。今回解いた問題はこちら。「A28 - Blackboard 」。それでは楽しんでいってください!

今回の問題のポイント

整数の性質がポイントでしたね。

足し算、引き算、掛け算では好きなタイミングで余りをとっても答え(余り)は変わらないっていうこと。これの競技プログラミングの鉄則、ぜひ買って読んでみてほしい。解説が分かりやすかったです。著者の米田さん。ありがとうございます。

自分がミスったポイント

  • 正しくコピペできていなかった。100010000だと思ってずっと苦戦していた。
  • Javaなので、Stringの値を比較するときはString.equals()にしないとですね。
  • 普通に一文字だけの時はcharactor使おう。そっちの方がめんどくさくなさそう。いや、Stringのメソッドたちも捨てにくい。
  • 無駄に長いコード。同じ意味のコードばかり繰り返している。だからまとめたよ!

目次

問題と公式の解説

問題

atcoder.jp

公式の解説

github.com

改良版 解答例

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();
        String[] t = new String[n];
        int[] a = new int[n];
        
        for (int i = 0; i < n; i++) {
            t[i] = sc.next();
            a[i] = sc.nextInt();
        }

        int ans = 0;
        for (int i = 0; i < n; i++) {
            ans = Divisor(t[i], a[i], ans);
            System.out.println(ans);
        }


    }

    private static int Divisor(String x, int y, int answer) {
        int value =  10000;

        if (x.equals("+")) {
            answer += y;
        }

        if (x.equals("-")) {
            answer -= y;
        }

        if (x.equals("*")) {
            answer *= y;
        }

        if (answer < 0) {
            answer += value;
        }

        answer %= value;
        return answer;        
    }
}

解答例

もう少し短くできますね。重複は削除しないとですよね^^.

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();
        String[] t = new String[n];
        int[] a = new int[n];
        
        for (int i = 0; i < n; i++) {
            t[i] = sc.next();
            a[i] = sc.nextInt();
        }

        int ans = 0;
        for (int i = 0; i < n; i++) {
            // System.out.println(t[i]);
            // System.out.println(a[i]);
            // System.err.println(ans);
            ans = Divisor(t[i], a[i], ans);
            System.out.println(ans);
        }


    }

    private static int Divisor(String x, int y, int answer) {

// 改良ポイント。tempに代入しようがしまいが、正味変わらない。上記の例(改良版 解答例)を参考にしてね。
        String tempX = x;
        int tempY = y;
        int tempAns = answer;
        int value =  10000;

        if (tempX.equals("+")) {
            tempAns += tempY;
        }

        if (tempX.equals("-")) {
            tempAns -= tempY;
        }

        if (tempX.equals("*")) {
            tempAns *= tempY;
        }

        if (tempAns < 0) {
            tempAns += value;
        }

        tempAns %= value;
        return tempAns;        
    }
}

Javaの解答例:学習記録:A27 - Calculate GCD , 競技プログラミングの鉄則 演習問題集

はじめに

競技プログラミングの鉄則 演習問題集の

問題のポイント

  • ユークリッドの互除法を使うこと
  • ユークリッドの互除法では大きい方を割り、余りを格納
  • 終了条件がどっちかが0になる。=両方が0でない。と同じ意味。

目次

問題と解説

問題

atcoder.jp

解説

github.com

解答例

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();

        System.out.println(GCD(a, b));
// 下記に関数を作って、そこで最大公約数を出しています!
    }

    private static int GCD(int x, int y) {
        int tempX = x;
        int tempY = y;
// 領邦とも0以上、どっちかが0になったらやめてほしいからこう書いています。
        while (tempX > 0 && tempY > 0) {
            if (tempX > tempY) {
                tempX %= tempY;
            } else {
                tempY %= tempX;
            }
        }
        

        if (tempX == 0) {
            return tempY;
        } else {
            return tempX;
        }
    }
}

ちなみに公式の解答例

import java.util.*;

class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        // 入力
        int A = sc.nextInt();
        int B = sc.nextInt();

        // 出力
        System.out.println(GCD(A, B));
    }

    // 正の整数 A と B の最大公約数を返す関数
    // GCD は Greatest Common Divisor(最大公約数)の略
    static int GCD(int A, int B) {
        while (A >= 1 && B >= 1) {
            if (A >= B) {
                A %= B; // A の値を変更する場合
            }
            else {
                B %= A; // B の値を変更する場合
            }
        }
        if (A >= 1) {
            return A;
        }
        return B;
    }
};