【ABC301】FortranでA,B,C問題


## A - Overall Winner
問題は[こちら](https://atcoder.jp/contests/abc301/tasks/abc301_a)です。
回答は以下の通りです。

試合の結果を全て調べ、高橋くんと青木くんの勝ち数を集計し判定しました。
勝ち数が同じ場合には、もう一度全試合の結果を調べて、どちらが先かを調べています。

```fortran
program ABC301a
    implicit none
    integer N, cnt_T, cnt_A, i, cnt
    character(:), allocatable :: S, T
    !入力
    READ (*, *) S, T

    !勝ち数集計
    cnt_A = 0
    cnt_T = 0
    do i = 1, N
        if (S(i:i) == "A") then
            cnt_A = cnt_A + 1
        else
            cnt_T = cnt_T + 1
        end if
    end do

    !結果判定
    if (cnt_A > cnt_T) then !A勝ち
        write (*, "(a)") 'A'
        stop
    else if (cnt_T > cnt_A) then !T勝ち
        write (*, "(a)") 'T'
        stop
    else if (cnt_T == cnt_A) then !勝ち数同じ
        cnt = cnt_A
        cnt_A = 0
        cnt_T = 0
        do i = 1, N
            if (S(i:i) == "A") then
                cnt_A = cnt_A + 1
            else
                cnt_T = cnt_T + 1
            end if
            if (cnt_A == cnt) then
                write (*, "(a)") 'A'
                stop
            else if (cnt_T == cnt) then
                write (*, "(a)") 'T'
                stop
            end if
        end do
    end if
end program
```

## B - Fill the Gaps
問題は[こちら](https://atcoder.jp/contests/abc301/tasks/abc301_b)です。
回答は以下の通りです。

初めに全配列を１つずつ調べ、A(i)とA(i+1)の差(絶対値)が１を超えるかを調べます。

差が１を超えない場合には、すぐに結果を表示して終了します。
差が１を超える場合には、その差の回数分A(i)から増減させた値を追加して、結果を表示し終了します。

```fortran
program ABC301b
    implicit none
    integer N, i, check, tuika, j, l, cnt
    integer, allocatable :: A(:), Ans(:)
    Ans = [integer ::]

    !入力
    READ (*, *) N
    allocate (A(N))
    READ (*, *) A

    !最初から全部絶対値１かチェック
    check = 0
    do i = 1, N - 1
        if (abs(A(i) - A(i + 1)) /= 1) then
            check = 1
            exit
        end if
    end do

    !最初から全部絶対値１なら終了
    if (check == 0) then
        write (*, '(*(i0, 1x))') A
        stop
    end if

    !数列の操作
    do i = 1, N - 1
        Ans = [Ans, A(i)]
        if (abs(A(i) - A(i + 1)) /= 1) then
            tuika = abs(A(i + 1) - A(i))
            l = 0
            if (A(i) < A(i + 1)) then
                do j = 1, tuika - 1
                    l = l + 1
                    Ans = [Ans, A(i) + l]
                end do
            elseif (A(i) > A(i + 1)) then
                do j = 1, tuika - 1
                    l = l + 1
                    Ans = [Ans, A(i) - l]
                end do
            end if
        end if
        !write (*, *) Ans
    end do
    Ans = [Ans, A(N)]
    write (*, '(*(i0, 1x))') Ans
end program

```

## C - AtCoder Cards
(自力では解けませんでした。他の回答者様の回答を参考にしています。)

初めにTとSのそれぞれの全てのカードを調べ、アルファベットと＠の出現回数を集計します。
集計の際には、[ASCIIコード](http://www3.nit.ac.jp/~tamura/ex2/ascii.html)を用いて文字を数字に変換し、それを配列の通し番号にして管理します。
（例えば、’A’はASCIIコードにすると97なので、alphabet(97)にAの出現回数を記録します。)

集計したTとSの結果を比較し、イカサマ可能or不可能かを調べます。
イカサマ可能な文字(a.t.c.o.d.e.r)かどうかについては、case文を用いて判別します。
併せてイカサマできる回数の上限(@の数)を管理し、最後までイカサマが成立しているかを調べます。

```fortran
program ABC301c
    implicit none
    integer s_alphabet(122), t_alphabet(122), i, s_length, t_a, s_a, diff
    character(200000):: S, T

    !S,T の入力
    read (*, *) S, T

    !@~zのそれぞれの個数を数える
    s_length = len_trim(S)
    s_alphabet = 0
    t_alphabet = 0
    do i = 1, s_length
        s_alphabet(iachar(S(i:i))) = s_alphabet(iachar(S(i:i))) + 1
        t_alphabet(iachar(T(i:i))) = t_alphabet(iachar(T(i:i))) + 1
    end do

    !イカサマで勝てるか判定
    t_a = t_alphabet(iachar("@"))
    s_a = t_alphabet(iachar("@"))
    do i = 97, 122
        diff = s_alphabet(i) - t_alphabet(i)
        !個数一致の場合
        if (diff == 0) cycle !イカサマorそのまま
        !個数不一致の場合
        select case (i)
            !置き換えできる文字の場合
        case (ichar("a"), ichar("t"), ichar("c"), ichar("o"), ichar("d"), ichar("e"), ichar("r"))
            !TとSのどちらが不足しているか
            if (diff > 0) then !tが不足
                !置き換え可能個数(@の総数)を超えないか
                t_a = t_a - diff
                if (t_a < 0) then !置き換え可能残数0
                    write (*, '(a)') "No"
                    stop
                end if
            else !sが不足
                !置き換え可能個数(@の総数)を超えないか
                s_a = s_a - diff
                if (s_a < 0) then !置き換え可能残数0
                    write (*, '(a)') "No"
                    stop
                end if
            end if
            !置き換え出来ない文字の場合
        case default
            write (*, '(a)') "No"
            stop
        end select
    end do

    write (*, '(a)') "Yes"
end
```


## 勉強になった事項
・　文字のカウントの管理には、ASCIIコードが有用であり、配列の通し番号として使える。ASCIIコードは``iachar("ここにもじ")``で取得できる。

・　複雑な分岐処理には、if文ではなく、``case文``が有用となる。

・　``cycle ``を使えば処理をスキップして次のループへ行ける。

・　``Ans = [Ans, A(i)]``で配列の要素数の追加ができる。(すごい)