AtCoder Beginner Contest 142をPHPで解く【PHP】

競技プログラミング

2019年9月28日(日)21:00~22:40に開かれました。AtCoder Beginner Contest 141に取り組みました。

AtCoder Beginner Contest(ABC)はプログラミングには興味あるけど、何をしていいわからない、そんな人のためのコンテンツです。

問題はAからFまでありだんだんと難しくなっていきます。

コンテスト開催時に参加できなかったため、手を付ける気にもなれず放置していました。
時間が空いてしまいましたが、過去問を解くつもりで再度取り組みたいと思います。

相変わらず自力だとD問題がACにならない。。。

A – Odds of Oddness

整数Nの中からランダムに1つの数字aを選んだ時のaが奇数である確率

奇数か偶数かのいずれかなので確率は2分の1、ではなく、Nが奇数の場合は奇数の数が偶数の数より1つ多いため確率が少し違う。

Nが偶数の時は奇数の数はN/2個、Nが奇数の時は奇数の数はN/2の商+1個ある。

これをそのまま実装すると

<?php
fscanf(STDIN, "%d", $n);
if ($n % 2 === 0) {
    $oddNum = $n / 2;
    echo $oddNum / $n;
} else if($n % 2 === 1) {
    $oddNum = intdiv($n, 2) + 1;
    echo $oddNum / $n;
}

ただ少し長いのでスッキリさせたいならNが奇数であろうと偶数であろうとceil()関数を使用すれば、ceil(N/2)で奇数の数になる。

B – Roller Coaster

要は、N個の中の要素からK以上のものが何個あるかを調べる問題。

for文でi番目の値がK以上であれば$ansを1追加、最終的な$ansが答え

<?php
fscanf(STDIN, "%d %d", $n, $k);
$h = explode(" ",fgets(STDIN));
$ans = 0;
for($i=0; $i<$n; $i++) {
    if($h[$i] >= $k) {
        $ans++;
    }
}
echo $ans;

こういう問題はfor文で解きがちだけど実際はforeach文を使ったほうがいいのか、ぱっと見ほかの人の解答コードを見ると大体の人がforeach文を使用している。for文使いがちなのでforeachも使っていきたいなとは思っている。

C – Go to School

生徒の登校した順番を知りたい。出席番号iの生徒が投稿した時点でAi人の生徒がいる(iの生徒を含む)ということなので、Aiを昇順に並べると教室にいた生徒の数が1人ずつ増えていく並びになる。その時のAiのキーが登校した順番を表しているにすぎない。

<?php
fscanf(STDIN, "%d", $n);
$a = explode(" ",(trim(fgets(STDIN))));
asort($a);
foreach($a as $key => $value) {
    echo ($key+1) . " ";
}

まずAをソートするが、ソート後の値とキーの関係は崩したくないのでsort()ではなくasort()を使用する。
あとは配列のキーの並びが答えそのものになっているためキーを取得できるforeach文を使用。

D – Disjoint Set of Common Divisors

正の整数A,Bの公約数からいくつか選び、選んだ整数の中のどの異なる2つの整数についても互いに素でなければいけない。

なんか難しそうなこと言ってるけど入力例1を見たら何となくイメージがつかめた。12と18の公約数が1,2,3,6のとき、これらをどのように2つ選んでも互いに素になるように抜き出す。

つまりA,Bの素数の中で共通のものが答え。

<?php
fscanf(STDIN, "%d %d", $a, $b);

$init = 2;
while ($a !== 1) {
$i = $init; while ($i < 0xFFFFFF) {
if ($a % $i == 0) {
$resultA[] = $i;
$a /= $i;
break;
} $i++;
}
$init = $i; }
$resultA = array_unique($resultA);

$init = 2;
while ($b !== 1) {
$i = $init; while ($i < 0xFFFFFF) {
if ($b % $i == 0) {
$resultB[] = $i;
$b /= $i;
break;
} $i++;
}
$init = $i; }
$resultB = array_unique($resultB);

$primeNumber = array_intersect($resultA, $resultB);

echo count($primeNumber) + 1;

A,Bに対して素因数分解を行ったのち、素数のみを取り出したいのでarray_unique()関数を使用、その後array_intersect()関数を使用して共通の要素を抜き出す。最後に1を足してこれが答え。

phpで素数を求める方法が分からなかったので、適当にググって出てきた記事を参考にしつつ、実装したコードがこちら、無事TLE。

考え方は間違っていないが、A,Bが非常に数の大きい素数だった場合にループが長くなってしまうと思われる。

じゃあどうするか、とりあえず解説とほかの人の解答を見る。なので0xFFFFFFをceil(sqrt($a))に変えてみたが変わらずTLE(むしろ悪くなった?)

コメント

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