htsign's blog

ノンジャンルで書くつもりだけど技術系が多いんじゃないかと思います

Paizaのオンラインハッカソンやってみた

土日特にすることもなく暇なので遊んでた。paiza.jp

1問目

与えられた文字列の基数番目のみを取り出せという問題。
使用言語: Ruby

input_lines = gets
chars = input_lines.each_char
odds = chars.select.with_index do |e, i| i % 2 == 0 end
puts odds.join

これは非常に簡単。どの言語使おうがすぐ書けます。
もしかしたら、「え?2で割り切れるのは偶数じゃないの?」と思うかもしれません。
ただ、プログラミング言語の世界ではインデックスは0から始まるのが主流であるため、この場合は逆転します。

2問目

曜日ごとの売り上げデータが改行区切りで流れてくるのでそれぞれ集計してね、という問題。
使用言語: C#

using System;
using System.Collections.Generic;
using System.Linq;

public class Hello{
    public static void Main(){
        var line = System.Console.ReadLine();
        int max = int.Parse(line);
        
        var weekDays = (DayOfWeek[])Enum.GetValues(typeof(DayOfWeek));
        var eachWeekDays = new Dictionary<DayOfWeek, List<int>>();
        foreach (DayOfWeek weekDay in weekDays)
        {
            eachWeekDays[weekDay] = new List<int>();
        }
        
        for (int i = 0; i < max; i++)
        {
            int value = int.Parse(Console.ReadLine());
            var week = (DayOfWeek)((i + 1) % 7);
            eachWeekDays[week].Add(value);
        }
        
        new[]{"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}
        .Select(s => (DayOfWeek)Enum.Parse(typeof(DayOfWeek), s))
        .Select(dow => eachWeekDays[dow])
        .ToList().ForEach(list => Console.WriteLine(list.Sum()));
    }
}

System.DayOfWeek列挙体にキャストするために無駄に回りくどいコードになってしまいました。
曜日ごとにList<int>を作って、それぞれに加算していって、最後に合計して出力、と。
正直読みにくい。こんなコード書いた奴は死ねばいいと思う。

3問目

RENA または MINAMI のどちらかを出力しろ、という問題。
正直Brainf*ck使っても5分以内に解ける自信があります。
コメントするべきことがないです。
使用言語: Ruby

puts :RENA

Rubyを使った理由は文字数が少なくて済むから。

4問目

RENAを選んだ場合の問題。
表計算ソフトの架空のシートで、選択した範囲の合計値を出力しろという問題。
選択範囲は複数の場合もありますが、セルの内容はすべて自然数です。
使用言語: C#

using System;
using System.Collections.Generic;
using System.Linq;

public class Hello
{
    public static void Main()
    {
        int[] intValues = Console.ReadLine().Trim().Split(' ').Select(int.Parse).ToArray();
        int columns     = intValues[0];
        int rows        = intValues[1];
        int selections  = intValues[2];
        
        Cell[,] cells = new Cell[columns, rows];
        
        for (int y = 0; y < rows; y++)
        {
            int[] values = Console.ReadLine().Trim().Split(' ').Select(int.Parse).ToArray();
            for (int x = 0; x < columns; x++)
            {
                cells[x, y].X = x;
                cells[x, y].Y = y;
                cells[x, y].Value = values[x];
            }
        }
        
        var selected = new HashSet<Cell>();
        for (int i = 0; i < selections; i++)
        {
            int[] positions = Console.ReadLine().Trim().Split(' ').Select(v => int.Parse(v) - 1).ToArray();
            int startX = positions[0];
            int startY = positions[1];
            int endX   = positions[2];
            int endY   = positions[3];
            
            cells.Cast<Cell>().Where(c =>
            {
                return
                    startX <= c.X && c.X <= endX &&
                    startY <= c.Y && c.Y <= endY;
            })
            .ToList().ForEach(c => selected.Add(c));
        }
        
        Console.WriteLine(selected.Sum(c => c.Value));
    }
}

struct Cell
{
    public int X { get; set; }
    public int Y { get; set; }
    public int Value { get; set; }
}

シート上のセルを表現するCell構造体を定義し、Cell型を持つ2次元配列を宣言、すべての要素に代入していきます。
選択範囲に含まれるセルをHashSet<Cell>に追加していきます。
HashSetクラス自体が内包するコレクションの重複を許さないため、追加する際に既に追加したかどうか、などと気にする必要がなくて楽です。
そしてHashSetクラスも当然のようにIEnumerable<T>を実装しているためLINQが使えます。
Cell構造体のValueプロパティを合計して出力、と。

余談ですが、この問題の問題文に書かれたプログラミングコードが「なでしこ」で書かれていて、コメントがいちいちエイプリルフールでやれといわんばかりの内容なので、是非一度見てみるといいと思います。

5問目

MINAMIを選んだ場合の問題。

まだやってません。
寝て起きたらやってみたいです。