競技プログラミングの鉄則    次の問題へ    前の問題へ

A57 Doubling


問題へのリンク


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("7 4");
            WillReturn.Add("2 4 1 7 6 5 3");
            WillReturn.Add("1 1");
            WillReturn.Add("1 5");
            WillReturn.Add("2 13");
            WillReturn.Add("5 999999999");
            //2
            //1
            //3
            //6
        }
        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>();

    static void Main()
    {
        List<string> InputList = GetInputList();
        long[] AArr = InputList[1].Split(' ').Select(pX => long.Parse(pX)).ToArray();
        long UB = AArr.GetUpperBound(0);

        for (long I = 0; I <= UB; I++) {
            AArr[I]--; // 0オリジンに変更
        }

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

        foreach (string EachStr in InputList.Skip(2)) {
            SplitAct(EachStr);
            XYInfoDef WillAdd;
            WillAdd.X = wkArr[0] - 1; // 0オリジンに変更
            WillAdd.Y = wkArr[1];
            mXYInfoList.Add(WillAdd);
        }

        // アリごとの現在位置[2べきの値]なDictの配列
        var DoublingDictArr = new Dictionary<long, long>[UB + 1];
        for (long I = 0; I <= UB; I++) {
            DoublingDictArr[I] = new Dictionary<long, long>();
        }

        // 1日後の位置を設定
        for (long I = 0; I <= UB; I++) {
            DoublingDictArr[I][1] = AArr[I];
        }

        // 2べき日後の位置を設定
        long MaxY = mXYInfoList.Max(pX => pX.Y);
        long Beki2 = 2;
        while (Beki2 <= MaxY) {
            long Div2 = Beki2 / 2;
            for (long I = 0; I <= UB; I++) {
                long Div2Pos = DoublingDictArr[I][Div2];
                long GoalPos = DoublingDictArr[Div2Pos][Div2];
                DoublingDictArr[I][Beki2] = GoalPos;
            }
            Beki2 *= 2;
        }

        // クエリに回答
        var sb = new System.Text.StringBuilder();
        foreach (XYInfoDef EachXYInfo in mXYInfoList) {
            long CurrPos = EachXYInfo.X;
            long RestDay = EachXYInfo.Y;

            while (RestDay > 0) {
                long MaxBeki2 = DeriveMaxBeki2(RestDay);
                CurrPos = DoublingDictArr[CurrPos][MaxBeki2];
                RestDay -= MaxBeki2;
            }
            sb.Append(CurrPos + 1); // 1オリジンに戻す
            sb.AppendLine();
        }
        Console.Write(sb.ToString());
    }

    // 引数の数値以下で、最大の2べきを返す
    static long DeriveMaxBeki2(long pTarget)
    {
        long WillReturn = 1;
        for (long I = 1; I < long.MaxValue; I *= 2) {
            if (I <= pTarget) {
                WillReturn = I;
            }
            else {
                break;
            }
        }
        return WillReturn;
    }
}


解説

ダブリングで解いてます。