競技プログラミング「AtCoder」をJavaScriptでやってみた その4

code

ABC193-B

問題「ゲーム機を買いに。販売しているのはN軒あり、店iは現在地から徒歩Ai分、販売価格Pi円、現在の在庫はXi台です。歩いて向かいあれば買えるが0.5,1.5,2.5分後に在庫が1台減る。買うことはできるか、その時の最小金額は?」

「N

A1 P1 X1

.

.

AN PN XN」

という入力ですが、これも例を見ないとわからない…例1は

「3

3 9 5

4 8 5

5 7 5」

店1に向かうと3分かかるので5台-3で着いた時2台あり9円で買えます。店2に向かうと4分かかるので5台-4で着いた時1台あり8円で買えます。店3に向かうと5分かかるので5台-5で着いた時在庫がないので買えません。答えは「8」

この問題も小さい方を求めるのでansを大きい数字にしておきます。

'use strict'
function main(input) {
  input = input.split("\n");
  let N = Number(input[0]);
  let ans = 100100100100;
 
  for(let i = 1; i <= N; i++) {
    let [a, p, x] = input[i].split(" ").map(Number);
    if(x > a && ans > p) {
      ans = p;
    }
  }
  if(ans === 100100100100) {
    ans = -1;
  }
  console.log(ans);
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));

for文の条件はinput[0]のNは要らないのでlet i = 1;1からNまでループします。そろぞれを[a, p, x]に分けて、在庫がかかる時間より大きく、ansより価格が安ければ買えますので、ansがその時の価格pになります。買えなかった場合はpがansより高いことは流石にないので、x > aが成立しない・在庫がなかった時でしょう。ansは書き換えられていないのでif(ans === 100100100100)の時ans = -1;になります。

ABC192-B

問題「先頭から奇数番目の文字が全て英小文字、偶数番目が英大文字、これを“読みにくい文字列”とする。Sが読みにくい文字か判定し、”Yes”か”No”か」

例1「dIfFiCuLt」は”Yes”で、例2「eASY」は”No”になります。問題文は簡単ですが、この時点で解法が浮かばないですよね。新しいtoLowerCasetoUpperCaseを使い小文字にしたり大文字にしたりの操作をします。

'use strict'
function main(input) {
  let items = input.trim().split("\n");
  let words = items[0].split("");
  let ans = "Yes";
 
  for(let i = 0; i < words.length; i++) {
    if(i % 2 === 0) {
        if(words[i] !== words[i].toLowerCase()) {
          ans = "No"; 
          break;
          }
      } else { 
        if(words[i] !== words[i].toUpperCase()) {
          ans = "No";
          break;
        }
      }
  }
  console.log(ans);
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));

変換もポイントですが、console.log(items)は[ ‘dIfFiCuLt’ ]になり、console.log(words);は[ ‘d’, ‘I’, ‘f’, ‘F’, ‘i’, ‘C’, ‘u’, ‘L’, ‘t’]です。let an s= ”Yes”で準備して、1つでも違ったら”No”にして関数を終える実装です。ifで奇数番目を表すのはi % 2 ===0 最初のi=0も2で割ると余りは0になります。

例えば1番目のwords[0]はdであり、words[0].toLowerCase()は「dを小文字にしたもの」になりますのでdのまま、「!==」は出ない時に”No”にしてbreak終了なのでwords[0]が終わった時点でansは”Yes”のまま次のwords[1]のループへ移ります。

ABC191-B

問題「長さNの整数列Aと整数X、AからXを除いたものを出力」

「N X

A1 A2 A3…AN」

これは問題文だけでも理解できるかと思いますが、一応例1を見ておきます。

「5 5

3 5 6 5 4」

[3,5,6,5,4]という5つの要素から5を除外すると、[3,6,4]です。ただアルゴリズムの方針は違うものをまとめて返す、そのためにfilterを使います。

'use strict'
function main(input) {
  input = input.trim().split("\n");
  let items = input.map((item)=>item.split(" ").map(Number));
  let N = items[0][0];
  let X = items[0][1];
  let A = items[1];
  const result = A.filter(n => n !== X);
    
  console.log(result.join(" "));
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));

Aは配列でそれをfilterにかけます。どのような処理をするかですが、それぞれ要素nを実行文に渡し、nがXと同じでない時、その同じでなかったものをresultに返します。今回は5と同じではない[3,6,4]がresultに返され、これを半角空白でまとめるjoin(“ ”)を出力。

ABC190-B

問題「N種類の魔法、i番目の呪文はXi秒かかり、威力はYiです。魔物にはS秒以上かかったり威力D以下の呪文はダメージを与えられない。ダメージを与えることができるか?YesかNoで」

「N S D

X1 Y1

.

.

XN YN」

という複雑な入力ですが、これも例を見れば仕組みはシンプルです。例1は

「4 9 9

5 5

15 5

5 15

15 15」

2,4番目は15なので9秒以上かかるのでなし、1,2番目は5で9以下なのでなし、つまり3番目の呪文はダメージを与えられるのでYes

'use strict'
function main(input) {
  input = input.trim().split("\n");
  let items = input.map((item)=>item.split(" ").map(Number));
  let N = items[0][0];
  let S = items[0][1];
  let D = items[0][2];
  let ans = "No";
  
  for(let i = 1; i <= N; i++) {
    let X = items[i][0];
    let Y = items[i][1];
    if(X < S && Y > D) {
      ans = "Yes";
      break;
    }
  }
  console.log(ans);
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));

特に説明することもないコードですが…ansをNoで用意しておいて、for文はitems[0]の4 9 9は要らないので、let i = 1からNまでループします。if文はS秒以下でかつ威力Dのものが1つでもあればその時点でansはYesにして終了break。問題文通りに書けば意外といけた系の問題でした。

ABC189-B

問題「N杯のお酒を飲んだ。i番目のお酒は量がVi ml、アルコール度数Pi %です。アルコール摂取量がX mlを超えると酔っぱらう。酔っぱらったのは何杯目を飲んだ時か?酔ってないなら-1を出力」

「N X

V1 P1

VN PN」

という入力で例1は

「2 15

200 5

350 3」

摂取量とパーセントの関係に注意して、計算して変換する必要があります。1杯目は200×(5÷100)で10mlのアルコールが含まれています。2杯目は350×(3÷100)で10.5mlのアルコールが含まれています。2杯目を飲んでいる時に15を超えるので出力するのは「2」

'use strict'
function main(input) {
  input = input.trim().split("\n");
  let items = input.map((item)=>item.split(" ").map(Number));
  let N = items[0][0];
  let X = items[0][1];
  let alc = 0;
  let ans = -1;
  
  for(let i = 1; i <= N; i++) {
    let V = items[i][0];
    let P = items[i][1];
    alc = alc + (V * P);
    if(alc > X * 100) {
      ans = i;
      break;
    } 
  }
  console.log(ans);
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));

アルコール摂取量をalc = 0、ansを酔わないことを想定し-1にしておきます。 この問題も問題文を理解すればその通りにコードを記述すればよさそうな問題ですが、実はちょっと問題がありました… コードテストではalc = alc + (V * P /100)で出力出来ていたのですが、提出するとなぜかWA… これでは小数点以下が切り捨てられてしまうため、そのままalcを足し上げていくと、その分の誤差が生じるのでした。よってif文の中でXの方を100倍し、それを積み上げたalcが超えたらansをその時のiにします。

ABC188-B

問題「2つのN次元ベクトルA=(A1,A2,A3,…AN)とA=(B1,B2,B3,…BN)があります。AとBの内積が0かどうかを判定」

何のこと?と思いますが、問題文にも書かれているようにA1B1+A2B2+A3B3…ANBN=0であれば”Yes”にします。入力は横に広がっていく形です。

「N

A1 A2 A3 … AN

B1 B2 B3 …BN」

例1は

「2

-3 6

4 2」

なので内積は(-3)×4 + 6×2 = 0になるので”Yes”

'use strict'
function main(input) {
  input = input.trim().split("\n");
  let items = input.map((item)=>item.split(" ").map(Number));
  let N = items[0];
  let total = 0;
  let ans = "No";
  
  for(let i = 0; i < N; i++) {
    let A = items[1][i];
    let B = items[2][i];
    total += (A * B);
  }
  
    if(total === 0) {
      ans = "Yes";
    } 
  console.log(ans);
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));

入力のAは2行目なのでitems[1][i]で、Bは3行目なのでitems[2][i]になりiが増えていくごとに右にズレていきます。掛け合わせたものをtotalに足し上げて、if文でtotalが0だったらansを”Yes”にします。

コメント

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