Avant-Garde Code

アバンギャルド・コード is 前衛的算譜.

ハイパー LINQ 集 (AtCoder 2020年1月)

2020年1月の AtCoder の問題を、LINQ (C#) を使って解いていきます。全8問。
問題文はそれぞれのリンク先を参照してください。

曲のリストを列挙し、曲名が X に一致するまでスキップします。
その一致した曲1つをスキップして、残りの再生時間の和を求めます。

using System;
using System.Linq;

class A
{
    static void Main()
    {
        var n = int.Parse(Console.ReadLine());
        var ms = new int[n].Select(_ => Console.ReadLine().Split()).ToArray();
        var x = Console.ReadLine();
        Console.WriteLine(ms.SkipWhile(m => m[0] != x).Skip(1).Sum(m => int.Parse(m[1])));
    }
}

本来は LINQ を使わずに解く問題なのですが、前問と同様にして解けます。
文字 a ~ z を列挙し、C に一致するまでスキップします。
その一致した文字1つをスキップして、最初に現れる文字を求めます。

using System;
using System.Linq;

class A
{
    static void Main()
    {
        var c = Console.ReadLine()[0];
        Console.WriteLine(Enumerable.Range('a', 26).Select(x => (char)x).SkipWhile(x => x != c).Skip(1).First());
    }
}

N * M から得点の合計を引いた値が最後のテストで必要となる点数です。
この値が K 以下であれば達成可能で、負である場合は 0 点でも達成可能です。

using System;
using System.Linq;

class B
{
    static int[] Read() => Console.ReadLine().Split().Select(int.Parse).ToArray();
    static void Main()
    {
        var h = Read();
        int n = h[0], k = h[1], m = h[2];
        var x = n * m - Read().Sum();
        Console.WriteLine(x <= k ? Math.Max(x, 0) : -1);
    }
}

入力を問題 ID でグループ化して提出結果に "AC" が含まれるものだけに絞り込み先頭から "WA" が続く回数を求めます。
このグループ数が正答数を、回数の和がペナルティ数を表します。

using System;
using System.Linq;

class C
{
    static void Main()
    {
        var h = Console.ReadLine().Split().Select(int.Parse).ToArray();
        var gs = new int[h[1]].Select(_ => Console.ReadLine().Split()).GroupBy(x => x[0], x => x[1]).Where(g => g.Contains("AC")).Select(g => g.TakeWhile(x => x == "WA").Count()).ToArray();
        Console.WriteLine($"{gs.Length} {gs.Sum()}");
    }
}

LINQ で簡潔に記述できる問題の中では難易度が高めです。
SK 個並べ、その後ろに  10^{9}N - K 個並べれば条件を満たします。
ただし、  S=10^{9} の場合は後ろに 1 を並べます。

using System;
using System.Linq;

class C
{
    static void Main()
    {
        var h = Console.ReadLine().Split().Select(int.Parse).ToArray();
        int n = h[0], k = h[1], s = h[2], M = 1000000000;

        var a = Enumerable.Repeat(s, k).Concat(Enumerable.Repeat(s == M ? 1 : M, n - k));
        Console.WriteLine(string.Join(" ", a));
    }
}

本来は LINQ を使わずに解く問題だと思いますが、別解として載せておきます。LINQ 力高め。
 P_1, \cdots , P_j の最小値を順に求めて  M_j に格納していきます。
そして  P_i \leq M_i を満たす i の個数を求めます。

using System;
using System.Linq;

class C
{
    static void Main()
    {
        var n = int.Parse(Console.ReadLine());
        var p = Console.ReadLine().Split().Select(int.Parse).ToArray();

        var m = new int[n];
        var j = 0;
        p.Aggregate(int.MaxValue, (a, x) => m[j++] = Math.Min(a, x));
        Console.WriteLine(Enumerable.Range(0, n).Count(i => p[i] <= m[i]));
    }
}

必殺技のダメージ量の和が H 以上となれば勝ちです。

using System;
using System.Linq;

class B
{
    static int[] Read() => Console.ReadLine().Split().Select(int.Parse).ToArray();
    static void Main()
    {
        var p = Read();
        var h = p[0];
        Console.WriteLine(Read().Sum() >= h ? "Yes" : "No");
    }
}

モンスターの体力を降順に並べ替えて先頭から K 回必殺技でスキップして残りの和を求めます。

using System;
using System.Linq;

class C
{
    static long[] Read() => Console.ReadLine().Split().Select(long.Parse).ToArray();
    static void Main()
    {
        var p = Read();
        var k = (int)p[1];
        Console.WriteLine(Read().OrderByDescending(x => x).Skip(k).Sum());
    }
}

バージョン

  • C# 8.0
    • .NET Core 3.1.201 で提出
    • 現行の AtCoder では、3種類の C# を選べる
    • 今回のコードは C# 6 でも可