ABC202-B
問題「0,1,6,8,9からなる文字列Sがあり、それを180度回転させたものを出力」
つまりabcdeをedcbaにして、6を9に9を6にするんですが、初めは「そんなのできるの?」と疑いました(笑) 入力は「S」です。ここでは新しいJavaScript技reverseを使います。
let array = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’];
let reversed = array.reverse();
console.log(reversed);
その名の通りreverse、これで[‘e’, ‘d’, ‘c’, ‘b’, ‘a’]になります。これができたらあとはif文で6だったら9に、9だったら6に、で出来そうですね。例1「0601889」は「6881090」にします。
'use strict'
function main(input) {
let S = input.trim().split("").map(Number);
for (let i = 0; i < S.length; i++) {
if(S[i] === 9) {
S[i] = 6;
} else if (S[i] === 6) {
S[i] = 9;
}
}
const answer = S.reverse().join("");
console.log(answer);
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));
見慣れない.join(“”)があります。実はこれもJavaScript技の1つで、「間に何も入らないようくっ付ける」を意味します。例えばjoin(“-”)だとハイフンでくっ付けることになり
let array = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’];
let joined = array.join(“-”);
console.log(joined);
これでa-b-c-d-eになります。join(“”)ではabcdeになることがイメージできるかと思います。for文でiはインデックス番号なので0から始めS.length例1では7なのでi<7まで回せば十分です。9を6に、6を9にしてからSをreverseして[6, 8, 8, 1, 0, 9, 0]でこれをjoin(“”)して6881090になります。
ABC201-B
問題「N個の山があり、i個目の山の名前はSi、高さはTiです。2番目に高い山のなまえは?」
入力は初めての形でNの数が決まっていないので
「N
S1 T1
S2 T2
.
.
.
Sn Tn」
こういう形になりますが、N以降はfor文でループを回すのでそこまで深く考えなくても大丈夫ですが、今回はJavaScript技が登場します。まず配列に要素を足していくpushは山の名前と高さを配列に後ろから格納します。
let colors = [‘red’, ‘green’, ‘blue’];
colors.push(‘pink’);
console.log(colors);
=>[‘red’, ‘green’, ‘blue’, ‘pink’];
になります。さらに207で出たsortを使って大きい順に並び変えて「2番目に高い山」なので前から2番目の情報を取り出します。
'use strict'
function main(input) {
input = input.trim().split("\n");
const N = Number(input[0]);
let array = [];
for (let i = 1; i <= N; i++) {
let [x, y] = input[i].trim().split(" ");
y = Number(y);
array.push([x, y]);
}
array.sort((a, b) => b[1] - a[1]);
console.log(array[1][0]);
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));
split(“\n”)(半角バックスラッシュn)改行で分けて、1行目を数値化しますが、parseInt(input[0], 10);でも可、空の配列arrayを用意して、そこに情報を入れます。for文でinput[0]はNなので、input[i]はinput[1]から始めるためi=1; i<=Nまで回します。次にinput[i]をsplitして[ ‘Everest’, ‘8849’ ]の形にしますが、一応数字なのでyは数値化してarrayにpush([x,y])します。例1だと3回繰り返して、この時点でconsole.log(array);すると[ [ ‘Everest’, 8849 ], [ ‘K2’, 8611 ], [ ‘Kangchenjunga’, 8586 ] ]になり配列の中に配列が入ります。(既に例が大きい順になってますね…)
次に並び替えsortは降順なのでarray.sort((a, b) => b[1] – a[1]); ここで[1]は各高さの数字が入り比較し、大きい順に並んだarrayの2番目[ ‘K2’, 8611 ],の最初の要素なのでarray[1][0]を出力します。
ABC200-B
問題「整数NにK回ある操作を行う。Nが200の倍数なら200で割る。でなければ、Nの後ろに200を付ける」
入力は「N K」 分かりにくいですが、例1は「2021 4」①2021は200の倍数でないので2021200になる、②2021200は200の倍数なので割って10106になる、③10106は違うので10106200、④10106200は200の倍数なので割って出力するのは「50531」このような操作をK回行う。
'use strict'
function main(input) {
input = input.trim().split(" ");
let N = Number(input[0]);
let K = Number(input[1]);
while(K > 0) {
if(N % 200 === 0) {
N /= 200;
} else {
N = (N * 1000) + 200;
}
K--;
}
console.log(N);
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));
for文を使う時のlet i = 0;などの定義が必要ないので、これはwhile文で書きました。回数Kを減らすイメージです。if文で剰余算「Nが200で割り切れるなら」Nを200で割り、そうでないならNに1000掛けて200を足す。200のために0を3つ用意してあげる感じでしょうか?忘れずにKをデクリメントし、Kが1を下回ったらwhile終わり。while(K >= 0)だと1回多く操作を行い「50531200」になるので注意。
ABC199-B
問題「長さNの数列A=(A1, A2, A3,…AN), B=(B1, B2, B3,…BN)がある。1≦ i ≦Nを満たす全ての整数iについてAi≦ x ≦Bi、xの個数は?」
問題文もよくわからないし、入力も新しい形
「N
A1, A2, A3 … AN
B1, B2, B3 … BN」
例1を見ると
「2
3 2
7 5」
3≦x≦7と2≦x≦5を満たすxは3,4,5の3つなので出力は「3」なんですが、いくつか線AiBiがあってその重なる部分を求めよ、ということです。
Ai—–Bi
Ai————-Bi
Ai—————–Bi
図にするとこんな感じでこの重なりはAiの最大値とBiの最小値の範囲になります。
'use strict'
function main(input) {
input = input.trim().split("\n");
let items = input.map((item)=>item.split(" ").map(Number));
const N = items[0];
const A = items[1];
const B = items[2];
const MAX_A = Math.max(...A);
const MIN_B = Math.min(...B);
let count = MIN_B - MAX_A + 1;
if(count < 0) {
count = 0;
console.log(count);
} else {
console.log(count);
}
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));
新しいのはMath.maxですがこれは「最大を出してね」で想像つくかと思います。使い方は注意console.log(A)だと[3, 2]になりconsole.log(…A)だと3 2になり、配列ではなく数値で使用するため「…」スプレッド構文で展開します。
例1では3≦x≦5なんですが、5-3では2になるので+1が必要になり、let count = MIN_B – MAX_A + 1; さらにif文でcountが重ならない0より小さい時はマイナスではなくcount=0にする。
ABC198-B
問題「整数Nがあり、Nの先頭に0個以上の0をつけて回文にできるか?」
例1では「1210」先頭に0を1つで「01210」で回文となり”Yes”で、また0個以上なので例2「777」は0を付けることなく「777」で”Yes”
入力は「N」だけなので改行で分ける必要はありません。末尾に0がある場合は先頭に0を付けられるということなので、回文の判定に必要なく、削ってしまいます。つまりNが10で割り切れるなら、かつ0でなければ、Nを10で割り続けます。例1ではこの時点で「121」なんですがこれは数値型であり、split()はString文字列を指定した文字列で区切るメソッドなのでNを文字列に変換。ちなみにtyprof(N)でnumberやstringを確認できます。ここまでで前半。
'use strict'
function main(input) {
let N = Number(input.trim());
while((N % 10 === 0) && (N !== 0)) {
N /= 10;
}
N = String(N);
const reverse_N = N.split("").reverse().join("");
if(N === reverse_N) {
console.log("Yes");
} else {
console.log("No");
}
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));
0を取り除いた文字列Nをsplit(“”)で区切りこの時点で「[‘1’, ‘2’, ‘1’]」になり、これをreverseでひっくり返し、それをjoinで繋げます。「どの型がsplitできる、この型ではreverseできない」などデータ型の扱いは慣れないと難しい…
このひっくり返したreverse_Nと入力されたNが等しければ”Yes”
197-Bは難しすぎるし、文字にできないのでパス…
4 4 2 2
##..
…#
#.#.
.#.#
の左上から(2,2)の位置から見える「.」の数は?のやつです。上下左右それぞれfor文の中にif文書いて”#”でなかったら
ABC196-B
問題「整数または少数Xがあり、小数点以下切り捨てて整数で出力」
制約は0≦X≦10**100
「Math.floor(input)じゃダメなのか?」と思いましたが、大きい数字の時は上手くいかないようで、アルゴリズムは「.」で区切って前の整数部分を出力します。trimやsplit(改行)もなく書けます。
'use strict'
function main(input) {
const N = input.split(".")[0];
console.log(N);
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));
typeof(input)で方を確認するとstringなのでその後のsplitが使えます。ちなみにinput.split(“.”)[1]は90です。
ABC195-B
問題「重さA~Bグラムのみかんがたくさん(整数とは限らない)、いくつか選んで重さWになった。個数として考えられる最小値・最大値を求めよ。合う個数がない時はUNSATISFIABLE」
問題文も例を見てもイメージしにくい問題です。例2の入力「120 150 2」みかん1個が120~150グラムで、これで2キロを作りますが、単位が違うのでWは1000倍します。個数を多くするには軽い方だけで2キロを作るためW割るA、反対に個数を減らすには重い方だけで2キロを作るためW割るB、なんですが… W÷A=16.6666…なので17個には届かないため小数点以下切り捨てます。W÷B=13.3333…個が必要で、つまり13個では2キロを作れないため切り上げて14にします。
'use strict'
function main(input) {
input = input.trim().split(" ");
let A = Number(input[0]);
let B = Number(input[1]);
let W = Number(input[2]);
W *= 1000;
const max = Math.floor(W/A);
const min = Math.ceil(W/B);
if(min > max){
console.log('UNSATISFIABLE');
} else {
console.log(min, max);
}
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));
if文の条件は同数は個数をそのまま出力するのでmin>maxの時だけ“UNSATISFIABLE”
ABC194-B
問題「N人の従業員、仕事A・Bを終えたい。従業員iは仕事AをAi分、仕事BをBi分でこなす。AとBに1人従業員を割り当てるが、同じ従業員でもいい。その場合それぞれの時間が掛かる。2つの仕事が終わる最短時間は?」
「3
8 5
4 4
7 9」
例1では仕事Aの最小は従業員2の4、Bの最小は4ですが同じ従業員2の4になってしまい、4+4で8分になってしまいます。よってBは従業員1に任せ5分となり、2人による別作業なので2つの仕事が終わるのは5分です。
「3
11 7
3 2
6 7」
例2は両方の仕事を従業員2に任せて3+2=5が最小になります。ここでアルゴリズムは複雑になりそうなことが想像できます…まずNとそれ以外に分けますが、スプレッド構文でまとめる書き方[N, …AB]をします。他の問題でもlet ans = 0を用意しておいて、あとからansを更新するものがありましたが、今回のように小さいものが求められる場合let min = 10001000など明らかに大きい数を用意しておいて、最終的に小さいものを出力するケースがあります。
'use strict'
function main(input) {
let [N, ...AB] = input.trim().split("\n");
let min = 10001000;
let sum_min = 0;
for(let i = 0; i < N; i++) {
for(let j = 0; j < N; j++) {
let A = Number(AB[i].split(" ")[0]);
let B = Number(AB[j].split(" ")[1]);
if(i === j) {
sum_min = A + B;
} else {
sum_min = Math.max(A, B);
}
min = Math.min(min, sum_min);
}
}
console.log(min);
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));
console.log(AB)は[‘8 5’, ‘4 4’, ‘7 9’]になり、console.log(…AB);は「8 5 4 4 7 9」です。
続いて2重ループで全ての要素を比較しますが、if文の下でconsole.log(sum_min)を出してみると「13 8 9 5 8 9 7 7 16」と流れが分かりやすいです。まずA=8のケースは8と5ですがこれはi===jなので(従業員が同じ)8+5=13、次は8と4を比べMath.max(8,4)で8、次は8と9を比べMath.max(8,9)で9、A=4のケースは4と5で5、4と4(従業員同じなので)4+4=8、4と9は9、このようなイメージです。
そして最初は10001000と13を比べMath.minなので小さい方13がminになり、毎回minとsum_minを比べ小さい方がminに入っていき、最終的にminを出力します。
コメント