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

ABC271-F XOR on Grid Path


問題へのリンク


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");
            WillReturn.Add("1 5 2");
            WillReturn.Add("7 0 5");
            WillReturn.Add("4 2 3");
            //2
        }
        else if (InputPattern == "Input2") {
            WillReturn.Add("2");
            WillReturn.Add("1 2");
            WillReturn.Add("2 1");
            //0
        }
        else if (InputPattern == "Input3") {
            WillReturn.Add("10");
            WillReturn.Add("1 0 1 0 0 1 0 0 0 1");
            WillReturn.Add("0 0 0 1 0 1 0 1 1 0");
            WillReturn.Add("1 0 0 0 1 0 1 0 0 0");
            WillReturn.Add("0 1 0 0 0 1 1 0 0 1");
            WillReturn.Add("0 0 1 1 0 1 1 0 1 0");
            WillReturn.Add("1 0 0 0 1 0 0 1 1 0");
            WillReturn.Add("1 1 1 0 0 0 1 1 0 0");
            WillReturn.Add("0 1 1 0 0 1 1 0 1 0");
            WillReturn.Add("1 0 1 1 0 0 0 0 0 0");
            WillReturn.Add("1 0 1 1 0 0 1 1 1 0");
            //24307
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

    static long[,] mBanArr;
    static long UB;

    static void Main()
    {
        List<string> InputList = GetInputList();

        mBanArr = CreateBanArr(InputList.Skip(1));
        UB = mBanArr.GetUpperBound(0);

        List<JyoutaiDef> SeiJyoutaiList = ExecDFS(false);
        List<JyoutaiDef> RevJyoutaiList = ExecDFS(true);

        // 件数[座標のハッシュ値,値] なDict
        var RevDict = new Dictionary<long, Dictionary<long, long>>();
        foreach (JyoutaiDef EachJyoutai in RevJyoutaiList) {
            long Hash = EachJyoutai.CurrX * 100 + EachJyoutai.CurrY;
            if (RevDict.ContainsKey(Hash) == false) {
                RevDict[Hash] = new Dictionary<long, long>();
            }

            long CurrXOR = EachJyoutai.XORVal;
            CurrXOR ^= mBanArr[EachJyoutai.CurrX, EachJyoutai.CurrY];
            if (RevDict[Hash].ContainsKey(CurrXOR) == false) {
                RevDict[Hash][CurrXOR] = 0;
            }
            RevDict[Hash][CurrXOR]++;
        }

        long Answer = 0;
        foreach (JyoutaiDef EachJyoutai in SeiJyoutaiList) {
            long Hash = EachJyoutai.CurrX * 100 + EachJyoutai.CurrY;
            if (RevDict.ContainsKey(Hash) == false) {
                continue;
            }
            long CurrXOR = EachJyoutai.XORVal;
            if (RevDict[Hash].ContainsKey(CurrXOR) == false) {
                continue;
            }
            Answer += RevDict[Hash][CurrXOR];
        }
        Console.WriteLine(Answer);
    }

    struct JyoutaiDef
    {
        internal long CurrX;
        internal long CurrY;
        internal long XORVal;
    }

    static List<JyoutaiDef> ExecDFS(bool pIsRev)
    {
        var WillReturn = new List<JyoutaiDef>();

        var Stk = new Stack<JyoutaiDef>();
        JyoutaiDef WillPush;

        if (pIsRev == false) {
            WillPush.CurrX = 0;
            WillPush.CurrY = 0;
            WillPush.XORVal = mBanArr[0, 0];
            Stk.Push(WillPush);
        }
        else {
            WillPush.CurrX = UB;
            WillPush.CurrY = UB;
            WillPush.XORVal = mBanArr[UB, UB];
            Stk.Push(WillPush);
        }

        while (Stk.Count > 0) {
            JyoutaiDef Popped = Stk.Pop();

            // クリア判定
            if (Popped.CurrX + Popped.CurrY == UB) {
                WillReturn.Add(Popped);
                continue;
            }

            Action<long, long> PushAct = (pNewX, pNewY) =>
            {
                WillPush.CurrX = pNewX;
                WillPush.CurrY = pNewY;
                WillPush.XORVal = Popped.XORVal ^ mBanArr[pNewX, pNewY];
                Stk.Push(WillPush);
            };

            if (pIsRev == false) {
                PushAct(Popped.CurrX, Popped.CurrY + 1);
                PushAct(Popped.CurrX + 1, Popped.CurrY);
            }
            else {
                PushAct(Popped.CurrX, Popped.CurrY - 1);
                PushAct(Popped.CurrX - 1, Popped.CurrY);
            }
        }
        return WillReturn;
    }

    ////////////////////////////////////////////////////////////////
    // IEnumerable<string>をintの2次元配列に設定する
    ////////////////////////////////////////////////////////////////
    static long[,] CreateBanArr(IEnumerable<string> pStrEnum)
    {
        var StrList = pStrEnum.ToList();
        if (StrList.Count == 0) {
            return new long[0, 0];
        }

        long[] IntArr = { };
        Action<string> SplitAct = pStr =>
            IntArr = pStr.Split(' ').Select(pX => long.Parse(pX)).ToArray();

        SplitAct(StrList[0]);

        long UB_X = IntArr.GetUpperBound(0);
        long UB_Y = StrList.Count - 1;

        long[,] WillReturn = new long[UB_X + 1, UB_Y + 1];

        for (long Y = 0; Y <= UB_Y; Y++) {
            SplitAct(StrList[(int)Y]);
            for (long X = 0; X <= UB_X; X++) {
                WillReturn[X, Y] = IntArr[X];
            }
        }
        return WillReturn;
    }
}


解説

8*8の盤面で考えます
 01234567
0□□□□□□□□
1□□□□□□□□
2□□□□□□□□
3□□□□□□□□
4□□□□□□□□
5□□□□□□□□
6□□□□□□□□
7□□□□□□□□

双方向に半分全探索すれば計算量を減らすことができますので、
双方向で●の箇所まで全探索してから、
逆方向の探索結果に前処理を行い、
正方向の探索結果と照合して、解を求めることができます。

 01234567
0□□□□□□□●
1□□□□□□●□
2□□□□□●□□
3□□□□●□□□
4□□□●□□□□
5□□●□□□□□
6□●□□□□□□
7●□□□□□□□