AtCoderのPAST    次のPASTの問題へ    前のPASTの問題へ

第9回PAST J 回転と反転


問題へのリンク


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 2");
            WillReturn.Add("1 1 1");
            WillReturn.Add("2 A");
            //001
            //000
            //000
        }
        else if (InputPattern == "Input2") {
            WillReturn.Add("3 3");
            WillReturn.Add("1 1 1");
            WillReturn.Add("3 A");
            WillReturn.Add("3 B");
            //000
            //000
            //001
        }
        else if (InputPattern == "Input3") {
            WillReturn.Add("4 8");
            WillReturn.Add("2 A");
            WillReturn.Add("1 4 2");
            WillReturn.Add("2 A");
            WillReturn.Add("1 2 2");
            WillReturn.Add("3 B");
            WillReturn.Add("3 B");
            WillReturn.Add("3 A");
            WillReturn.Add("1 3 1");
            //0000
            //0000
            //0100
            //0000
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

    static int[,] mMatrix90Do;
    static int[,] mMatrix270Do;
    static int[,] mMatrixRevYoko;
    static int[,] mMatrixRevTate;

    static decimal mN;
    static decimal mGenten;

    static void Main()
    {
        List<string> InputList = GetInputList();
        string Result = Solve(InputList);
        Console.Write(Result);
    }

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

    static int UB;

    static string Solve(List<string> pInputList)
    {
        int[] wkArr = GetSplitArr(pInputList[0]);
        mN = wkArr[0];
        UB = wkArr[0] - 1;

        Init();

        byte[,] BanArr = new byte[UB + 1, UB + 1];

        // 後続の座標変換の行列
        int[,] AfterMatrixArr = DeriveUnitMatrix(1);

        // クエリを逆から走査
        for (int I = pInputList.Count - 1; 1 <= I; I--) {
            string[] SplitArr = pInputList[I].Split(' ');
            int Type = int.Parse(SplitArr[0]);
            if (Type == 1) {
                decimal Y = decimal.Parse(SplitArr[1]) - 1;
                decimal X = decimal.Parse(SplitArr[2]) - 1;

                ExecHenkan1_2(ref X, ref Y);
                SetPos(ref X, ref Y, AfterMatrixArr);
                ExecHenkan2_1(ref X, ref Y);

                BanArr[(int)X, (int)Y]++;
                BanArr[(int)X, (int)Y] %= 2;
            }
            if (Type == 2) {
                if (SplitArr[1] == "A") {
                    // 90度回転
                    AfterMatrixArr = DeriveMatrixProd(mMatrix90Do, AfterMatrixArr);
                }
                if (SplitArr[1] == "B") {
                    // 270度回転
                    AfterMatrixArr = DeriveMatrixProd(mMatrix270Do, AfterMatrixArr);
                }
            }
            if (Type == 3) {
                if (SplitArr[1] == "A") {
                    // 上下反転
                    AfterMatrixArr = DeriveMatrixProd(mMatrixRevTate, AfterMatrixArr);
                }
                if (SplitArr[1] == "B") {
                    // 左右反転
                    AfterMatrixArr = DeriveMatrixProd(mMatrixRevYoko, AfterMatrixArr);
                }
            }
        }

        // 解を出力
        var sb = new System.Text.StringBuilder();
        for (int Y = 0; Y <= UB; Y++) {
            for (int X = 0; X <= UB; X++) {
                sb.Append(BanArr[X, Y]);
            }
            sb.AppendLine();
        }
        return sb.ToString();
    }

    static void Init()
    {
        mGenten = mN / 2M;

        // 行列なので[行,列]という持ち方
        mMatrix90Do = new int[,] {{0,-1},
                                  {1,0}};

        // 行列なので[行,列]という持ち方
        mMatrix270Do = new int[,] {{0,1},
                                   {-1,0}};

        // 行列なので[行,列]という持ち方
        mMatrixRevYoko = new int[,] {{-1,0},
                                     {0,1}};

        // 行列なので[行,列]という持ち方
        mMatrixRevTate = new int[,] {{1,0},
                                     {0,-1}};
    }

    // 座標系1の(X,Y)を座標系2の(X,Y)に変換
    static void ExecHenkan1_2(ref decimal pX, ref decimal pY)
    {
        pX += 0.5M;
        pX -= mGenten;

        pY += 0.5M;
        pY -= mGenten;
        pY *= -1;
    }

    // 座標系2の(X,Y)を座標系1の(X,Y)に変換
    static void ExecHenkan2_1(ref decimal pX, ref decimal pY)
    {
        pX += mGenten;
        pX -= 0.5M;

        pY *= -1;
        pY += mGenten;
        pY -= 0.5M;
    }

    // 座標系2の(X,Y)を後続のクエリ後の座標に変換
    static void SetPos(ref decimal pX, ref decimal pY, int[,] pAfterMatrixArr)
    {
        decimal BeforeX = pX;
        decimal BeforeY = pY;
        pX = pAfterMatrixArr[0, 0] * BeforeX + pAfterMatrixArr[1, 0] * BeforeY;
        pY = pAfterMatrixArr[0, 1] * BeforeX + pAfterMatrixArr[1, 1] * BeforeY;
    }

    // 単位行列を返す
    static int[,] DeriveUnitMatrix(int UB)
    {
        int[,] WillReturn = new int[UB + 1, UB + 1];
        for (int LoopY = 0; LoopY <= UB; LoopY++) {
            for (int LoopX = 0; LoopX <= UB; LoopX++) {
                if (LoopY == LoopX) {
                    WillReturn[LoopY, LoopX] = 1;
                }
            }
        }
        return WillReturn;
    }

    // 正方行列2つの積を返す
    static int[,] DeriveMatrixProd(int[,] pMatrix1, int[,] pMatrix2)
    {
        int UB = pMatrix1.GetUpperBound(0);

        // 横の値の配列[行]
        var YokoArrDict = new Dictionary<int, int[]>();
        for (int LoopY = 0; LoopY <= UB; LoopY++) {
            var YokoList = new List<int>();
            for (int LoopX = 0; LoopX <= UB; LoopX++) {
                YokoList.Add(pMatrix1[LoopY, LoopX]);
            }
            YokoArrDict[LoopY] = YokoList.ToArray();
        }

        // 縦の値の配列[列]
        var TateArrDict = new Dictionary<int, int[]>();
        for (int LoopX = 0; LoopX <= UB; LoopX++) {
            var TateList = new List<int>();
            for (int LoopY = 0; LoopY <= UB; LoopY++) {
                TateList.Add(pMatrix2[LoopY, LoopX]);
            }
            TateArrDict[LoopX] = TateList.ToArray();
        }

        int[,] MatrixProd = new int[UB + 1, UB + 1];
        for (int LoopY = 0; LoopY <= UB; LoopY++) {
            for (int LoopX = 0; LoopX <= UB; LoopX++) {
                int SumVal = 0;
                for (int K = 0; K <= UB; K++) {
                    SumVal += (YokoArrDict[LoopY][K] * TateArrDict[LoopX][K]);
                }
                MatrixProd[LoopY, LoopX] = SumVal;
            }
        }
        return MatrixProd;
    }
}


解説

クエリを逆から見てます。
指定座標を反転する処理があったら、
後続の座標変換の行列表現での総積から、最終的な座標を求め、その座標を反転してます。

原点を中心として回転
X軸を基準とした反転
Y軸を基準とした反転
の組み合わせで解くために、
盤面の中心を原点とした、数学の座標系と
盤面の左上を原点とした、コンピュータ座標系の
相互変換もしてます。