AtCoderのABC    次のABCの問題へ    前のABCの問題へ

ABC466-D Placing Rooks


問題へのリンク


C#のソース

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

class Program
{
    static string InputPattern = "InputX";

    static List<string> GetInputList()
    {
        var WillReturn = new List<string>();

        if (InputPattern == "Input1") {
            WillReturn.Add("3 6");
            WillReturn.Add("1 1");
            WillReturn.Add("1 2");
            WillReturn.Add("3 3");
            WillReturn.Add("3 2");
            WillReturn.Add("1 3");
            WillReturn.Add("1 3");
            //2
        }
        else if (InputPattern == "Input2") {
            WillReturn.Add("2 3");
            WillReturn.Add("1 2");
            WillReturn.Add("2 1");
            WillReturn.Add("1 1");
            //1
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

    static long[] GetSplitArr(string pStr)
    {
        return (pStr == "" ? new string[0] : pStr.Split(' ')).Select(pX => long.Parse(pX)).ToArray();
    }

    static void Main()
    {
        List<string> InputList = GetInputList();
        long[] wkArr = GetSplitArr(InputList[0]);
        long N = wkArr[0];

        // RookのY座標のSet[X座標]
        var XSetDict = new Dictionary<long, HashSet<long>>();

        // RookのX座標のSet[Y座標]
        var YSetDict = new Dictionary<long, HashSet<long>>();

        for (long I = 1; I <= N; I++) {
            XSetDict[I] = new HashSet<long>();
            YSetDict[I] = new HashSet<long>();
        }

        // (X,Y)のRookを消す
        Action<long, long> RemoveRook = (pX, pY) =>
        {
            XSetDict[pY].Clear();
            YSetDict[pX].Clear();
        };

        Action<string> SplitAct = (pStr) => wkArr = GetSplitArr(pStr);
        foreach (string EachStr in InputList.Skip(1)) {
            SplitAct(EachStr);
            long TargetY = wkArr[0];
            long TargetX = wkArr[1];

            foreach (long EachX in XSetDict[TargetY].ToArray()) {
                RemoveRook(EachX, TargetY);
            }
            foreach (long EachY in YSetDict[TargetX].ToArray()) {
                RemoveRook(TargetX, EachY);
            }

            XSetDict[TargetY].Add(TargetX);
            YSetDict[TargetX].Add(TargetY);
        }

        long Answer = 0;
        for (long I = 1; I <= N; I++) {
            Answer += XSetDict[I].Count;
            Answer += YSetDict[I].Count;
        }
        Console.WriteLine(Answer / 2);
    }
}


解説

8王妃問題のルークで行うと考えることができます。

ダイソーのオセロセットで考察すると、
□□□□□□R□
□□□R□□□□
□□R□□□□□
□R□□□□□□
□□□□R□□□
□□□□□□□R
□□□□□R□□
R□□□□□□□

新たにルークを置く際に
同じY座標のルークと、同じX座標のルークの位置を高速に取得でき、
削除も高速にできれば良いと分かります。

これには、
ルークのX座標のSet[Y座標]と
ルークのY座標のSet[X座標]を持ち、

ルークを削除する際は、
ルークの座標を引数としたラムダ式を用意しておいて、
呼べば良いと分かります。

最後には、
ルークのX座標のSet[Y座標]と
ルークのY座標のSet[X座標]を集計し、
2で割れば解が分かります。