AtCoder に登録したら解くべき精選過去問 10 問を JavaScript で解いてみた

[AtCoder に登録したら次にやること ～ これだけ解けば十分闘える！過去問精選 10 問 ～](https://qiita.com/drken/items/fd4e5e3630d0f5859067#%E7%AC%AC-10-%E5%95%8F--abc-086-c---traveling-300-%E7%82%B9)で
紹介されていた問題をJavaScript(Node.js)で解いてみました。

他言語で解いた記事はありますが、まだJavaScript版がない。
そして競技プログラミングだとJavaScriptはあまり使われない印象なので、
今回はあえてJavaScriptで挑みました。

競技プログラミングの問題を解くのが初なので、
最適解にはなっていないかもしれませんが、ご了承ください。

※問題の解説については、上記記事にわかりやすい解法が載っているので割愛します。

# 標準入出力

[ここ](https://language-test-201603.contest.atcoder.jp/tasks/practice_1#)の「JavaScript(Node.js) での解答例」が非常にわかりやすいです。

```javascript:こんな感じ
function main(input) {
    console.log(input);
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));
```

# 第1問: [ABC 086 A - Product](https://beta.atcoder.jp/contests/abc086/tasks/abc086_a)

二つの整数 a,bの積の偶奇を判定する。

```javascript
function main(input) {
    const args = input.split(' ');
    const a = parseInt(args[0], 10);
    const b = parseInt(args[1], 10);

    if ((a * b) % 2 === 0) {
        console.log('Even');
    } else {
        console.log('Odd');
    }
}

main(require('fs').readFileSync('/dev/stdin', 'utf8'));
```

# 第2問: [ABC 081 A - Placing Marbles](https://beta.atcoder.jp/contests/abc081/tasks/abc081_a)

文字列内の、1の個数をカウントする。

```javascript
function main(input) {
    console.log(input.split('1').length - 1);
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));
```

# 第3問: [ABC 081 B - Shift Only](https://beta.atcoder.jp/contests/abc081/tasks/abc081_b)

N個の整数を同時に、割り切れなくなるまで割っていった場合、何回割ることができるかを求める。

```javascript
function main(input) {
    var nums = input.split('\n')[1].split(' ').map((n) => parseInt(n, 10));

    var count = 0;
    while(nums.every((n) => (n % 2) === 0)) {
        count++;
        nums = nums.map((n) => n / 2);
    }
    
    console.log(count);
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));
```

# 第4問: [ABC 087 B - Coins](https://beta.atcoder.jp/contests/abc087/tasks/abc087_b)

500円玉、100円玉、50円玉を使ってX円を支払う方法が何通りあるかを求める。

```javascript
function main(input) {
    const args = input.split('\n');
    const A = parseInt(args[0], 10),
          B = parseInt(args[1], 10),
          C = parseInt(args[2], 10),
          X = parseInt(args[3], 10);

    var count = 0;

    for (var a = 0; a <= A; ++a) {
        for (var b = 0; b <= B; ++b) {
            for (var c = 0; c <= C; ++c) {
                var sum = (a * 500) + (b * 100) + (c * 50);
                if (sum === X) ++count;
            }
        }
    }
    console.log(count);
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));
```

# 第5問: [ABC 083 B - Some Sums](https://beta.atcoder.jp/contests/abc083/tasks/abc083_b)

1以上N以下の整数のうち、各桁の和がA以上B以下であるものの総和を求める。

```javascript
function main(input) {
    const args = input.split(' ');
    const N = parseInt(args[0], 10),
          A = parseInt(args[1], 10),
          B = parseInt(args[2], 10);

    const nums = Array.from(new Array(N), (v, i) => ++i).filter((i) => {
        var n = i.toString().split('').reduce((p, c) => p + parseInt(c), 0);
        return (n >= A && n <= B);
    });
    
    console.log(nums.reduce((p, c) => p + c, 0));
}

main(require('fs').readFileSync('/dev/stdin', 'utf8'));
```

# 第6問: [ABC 088 B - Card Game for Two](https://beta.atcoder.jp/contests/abc088/tasks/abc088_b)

N枚のカードを交互に自身の得点が最大になるように取っていった場合の、二人の得点の差分を求める。

```javascript
function main(input) {
    const args = input.split('\n');
    const N = parseInt(args[0], 10),
          cards = args[1].split(' ').map(n => parseInt(n, 10));

    var aSum = 0,
        bSum = 0;

    cards.sort((a, b) => (a < b ? 1 : -1)).forEach((n, i) => {
        (i % 2 === 0)? aSum += n : bSum += n;
    });

    console.log(aSum - bSum);
}

main(require('fs').readFileSync('/dev/stdin', 'utf8'));
```

# 第7問: [ABC 085 B - Kagami Mochi](https://beta.atcoder.jp/contests/abc085/tasks/abc085_b)

N個の整数の重複しない値の数を求める。

```javascript
function main(input) {
    const args = input.split('\n');
    const N = args[0],
          nums = args.slice(1, args.length - 1);
    
    console.log(nums.filter((n, i) => nums.indexOf(n) === i).length);
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));
```

# 第8問: [ABC 085 C - Otoshidama](https://beta.atcoder.jp/contests/abc085/tasks/abc085_c)

10000円札、5000円札、1000円札がある前提で、合計がN枚、Y円になる組み合わせを求める。

```javascript
function main(input) {
    const args = input.split(' ');
    const N = parseInt(args[0], 10),
          Y = parseInt(args[1], 10);

    var result = '-1 -1 -1';
    
    for (var a = 0; a <= N; a++) {
        for (var b = 0; b <= N; b++) {
            if ((a + b) > N) {
                continue;
            }

            var sum = (a * 10000) + (b * 5000) + ((N - a - b) * 1000);
            if (sum === Y) {
                result = `${a} ${b} ${N - a - b}`;
                break;
            }
        }        
    }
    
    console.log(result);

}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));
```

# 第9問: [ABC 049 C - Daydream](https://beta.atcoder.jp/contests/abc049/tasks/arc065_a)

文字列Sが、"dream", "dreamer", "erase", "eraser"の組み合わせで作れるかどうかを判定する。

```javascript
function main(input) {
    const reverse = (s) => {
        return s.split('').reverse().join('');
    };

    const WORDS = ['dream', 'dreamer', 'erase', 'eraser'].map(reverse);
    const S = reverse(input.split('\n')[0]);

    var index = 0;
    
    while(true) {
        var w = WORDS.find((w) => S.startsWith(w, index));
        if (!w) break;
        index += w.length;
    }

    if (S.length === index) {
        console.log('YES');
    } else {
        console.log('NO');
    }
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));
```

# 第10問: [ABC 086 C - Traveling](https://beta.atcoder.jp/contests/abc086/tasks/arc089_a)

座標(0, 0)を出発地点とした場合、時刻ti時点で(xi, yi)にいることができるかどうかを判定する。

```javascript
function main(input) {
    const args = input.split('\n');
    const N = parseInt(args[0], 10);
    const nums = args.slice(1, N + 1);
    const isValid = nums.every((n) => {
        var ns = n.split(' ');
        var t = parseInt(ns[0], 10),
            x = parseInt(ns[1], 10),
            y = parseInt(ns[2], 10);
        var sum = x + y;

        return (t >= sum) && ((t % 2) === (sum % 2));
    });

    if (isValid) {
        console.log('Yes');
    } else {
        console.log('No');
    }
}
main(require('fs').readFileSync('/dev/stdin', 'utf8'));
```

# おわりに
[分割代入](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)を使いたい場面が多々あるので、Node.jsのサポートバージョンが**v5.12**なのが少し残念。
このバージョンだとサポートされていない...。(近いうちにサポートバージョンが上がるはず！)

次はもう少し難しい問題にも挑戦してみようと思います。もちろんJavaScriptで。