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

ABC189-E Rotate and Flip


問題へのリンク


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

    struct XYInfoDef
    {
        internal long X;
        internal long Y;
    }
    static List<XYInfoDef> mXYInfoList = new List<XYInfoDef>();

    struct OPInfoDef
    {
        internal long Type;
        internal long P;
    }
    static List<OPInfoDef> mOPInfoList = new List<OPInfoDef>();

    struct QInfoDef
    {
        internal long A;
        internal long B;
    }
    static List<QInfoDef> mQInfoList = new List<QInfoDef>();
    static Queue<QInfoDef> mQInfoQue;

    // クエリの回答[クエリのハッシュ値]
    static Dictionary<string, string> mAnswerDict = new Dictionary<string, string>();

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

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

        long N = long.Parse(InputList[0]);
        foreach (string EachStr in InputList.Skip(1).Take((int)N)) {
            SplitAct(EachStr);
            XYInfoDef WillAdd;
            WillAdd.X = wkArr[0];
            WillAdd.Y = wkArr[1];
            mXYInfoList.Add(WillAdd);
        }

        long M = long.Parse(InputList[(int)N + 1]);
        foreach (string EachStr in InputList.Skip((int)N + 2).Take((int)M)) {
            SplitAct(EachStr);
            OPInfoDef WillAdd;
            WillAdd.Type = wkArr[0];
            WillAdd.P = int.MinValue;
            if (wkArr[0] == 3 || wkArr[0] == 4) {
                WillAdd.P = wkArr[1];
            }
            mOPInfoList.Add(WillAdd);
        }

        foreach (string EachStr in InputList.Skip(1 + (int)N + 1 + (int)M + 1)) {
            SplitAct(EachStr);
            QInfoDef WillAdd;
            WillAdd.A = wkArr[0];
            WillAdd.B = wkArr[1];
            mQInfoList.Add(WillAdd);
        }
        // クエリのキューも用意しておく
        mQInfoQue = new Queue<QInfoDef>(mQInfoList.OrderBy(pX => pX.A));

        Solve();
    }

    // 初期座標を(a,b)として、座標変換の累積情報
    struct HenkanInfoDef
    {
        internal long X_Keisuu_a;
        internal long X_Keisuu_b;
        internal long X_Tesuu;
        internal long Y_Keisuu_a;
        internal long Y_Keisuu_b;
        internal long Y_Tesuu;
    }

    static void Solve()
    {
        HenkanInfoDef CurrHenkanInfo;
        CurrHenkanInfo.X_Keisuu_a = 1;
        CurrHenkanInfo.X_Keisuu_b = 0;
        CurrHenkanInfo.X_Tesuu = 0;
        CurrHenkanInfo.Y_Keisuu_a = 0;
        CurrHenkanInfo.Y_Keisuu_b = 1;
        CurrHenkanInfo.Y_Tesuu = 0;

        for (long I = 0; I <= mOPInfoList.Count; I++) {
            while (mQInfoQue.Count > 0) {
                long PeekA = mQInfoQue.Peek().A;
                long PeekB = mQInfoQue.Peek().B;
                if (PeekA == I) {
                    long BFirstX = mXYInfoList[(int)PeekB - 1].X;
                    long BFirstY = mXYInfoList[(int)PeekB - 1].Y;

                    string Pos = GetPos(CurrHenkanInfo, BFirstX, BFirstY);
                    string Hash = string.Format("{0},{1}", PeekA, PeekB);
                    mAnswerDict[Hash] = Pos;

                    mQInfoQue.Dequeue();
                }
                else {
                    break;
                }
            }
            if (I == mOPInfoList.Count) break;

            long CurrType = mOPInfoList[(int)I].Type;
            long CurrP = mOPInfoList[(int)I].P;

            if (CurrType == 1) AddHenkan1(ref CurrHenkanInfo);
            if (CurrType == 2) AddHenkan2(ref CurrHenkanInfo);
            if (CurrType == 3) AddHenkan3(ref CurrHenkanInfo, CurrP);
            if (CurrType == 4) AddHenkan4(ref CurrHenkanInfo, CurrP);
        }

        foreach (QInfoDef EachQInfo in mQInfoList) {
            string Hash = string.Format("{0},{1}", EachQInfo.A, EachQInfo.B);
            Console.WriteLine(mAnswerDict[Hash]);
        }
    }

    // 初期座標と累積変換を引数として、現在の座標を返す
    static string GetPos(HenkanInfoDef pHenkanInfo, long a, long b)
    {
        long X = 0;
        X += pHenkanInfo.X_Keisuu_a * a;
        X += pHenkanInfo.X_Keisuu_b * b;
        X += pHenkanInfo.X_Tesuu;

        long Y = 0;
        Y += pHenkanInfo.Y_Keisuu_a * a;
        Y += pHenkanInfo.Y_Keisuu_b * b;
        Y += pHenkanInfo.Y_Tesuu;

        return string.Format("{0} {1}", X, Y);
    }

    // 累積変換に変換1(時計周りに90度)を行う
    static void AddHenkan1(ref HenkanInfoDef pHenkanInfo)
    {
        HenkanInfoDef Before = pHenkanInfo;
        pHenkanInfo.X_Keisuu_a = Before.Y_Keisuu_a;
        pHenkanInfo.X_Keisuu_b = Before.Y_Keisuu_b;
        pHenkanInfo.X_Tesuu = Before.Y_Tesuu;
        pHenkanInfo.Y_Keisuu_a = -(Before.X_Keisuu_a);
        pHenkanInfo.Y_Keisuu_b = -(Before.X_Keisuu_b);
        pHenkanInfo.Y_Tesuu = -(Before.X_Tesuu);
    }

    // 累積変換に変換2(反時計周りに90度)を行う
    static void AddHenkan2(ref HenkanInfoDef pHenkanInfo)
    {
        HenkanInfoDef Before = pHenkanInfo;
        pHenkanInfo.X_Keisuu_a = -(Before.Y_Keisuu_a);
        pHenkanInfo.X_Keisuu_b = -(Before.Y_Keisuu_b);
        pHenkanInfo.X_Tesuu = -(Before.Y_Tesuu);
        pHenkanInfo.Y_Keisuu_a = Before.X_Keisuu_a;
        pHenkanInfo.Y_Keisuu_b = Before.X_Keisuu_b;
        pHenkanInfo.Y_Tesuu = Before.X_Tesuu;
    }

    // 累積変換に変換3(直線X=Pで対称移動)を行う
    static void AddHenkan3(ref HenkanInfoDef pHenkanInfo, long pP)
    {
        // Y座標は変化しない
        // X座標は、直線X=Pを中点とした、対称移動
        pHenkanInfo.X_Keisuu_a *= -1;
        pHenkanInfo.X_Keisuu_b *= -1;
        pHenkanInfo.X_Tesuu *= -1;
        pHenkanInfo.X_Tesuu += 2 * pP;
    }

    // 累積変換に変換4(直線Y=Pで対称移動)を行う
    static void AddHenkan4(ref HenkanInfoDef pHenkanInfo, long pP)
    {
        // X座標は変化しない
        // Y座標は、直線Y=Pを中点とした、対称移動
        pHenkanInfo.Y_Keisuu_a *= -1;
        pHenkanInfo.Y_Keisuu_b *= -1;
        pHenkanInfo.Y_Tesuu *= -1;
        pHenkanInfo.Y_Tesuu += 2 * pP;
    }
}


解説

(a,b)を90度回転移動した座標は
(b,-a)と表せます。

(a,b)を直線X=5に対して、対称移動した座標は、
Y座標は、変わらなくて
X座標は、移動後のX座標を?とすると
中点を考えて
(a+?) / 2 = 5 で
? = 10-a
となります。

後は、変換を行うごとに初期座標を(a,b)とした時の
X座標のaとbと定数
Y座標のaとbと定数
を変更するようにしてます。