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

ABC321-E Complete Binary Tree


問題へのリンク


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("5");
            WillReturn.Add("10 2 0");
            WillReturn.Add("10 2 1");
            WillReturn.Add("10 2 2");
            WillReturn.Add("10 2 3");
            WillReturn.Add("10 2 4");
            //1
            //3
            //4
            //2
            //0
        }
        else if (InputPattern == "Input2") {
            WillReturn.Add("10");
            WillReturn.Add("822981260158260522 52 20");
            WillReturn.Add("760713016476190629 2314654 57");
            WillReturn.Add("1312150450968417 1132551176249851 7");
            WillReturn.Add("1000000000000000000 1083770654 79");
            WillReturn.Add("234122432773361868 170290518806790 23");
            WillReturn.Add("536187734191890310 61862 14");
            WillReturn.Add("594688604155374934 53288633578 39");
            WillReturn.Add("1000000000000000000 120160810 78");
            WillReturn.Add("89013034180999835 14853481725739 94");
            WillReturn.Add("463213054346948152 825589 73");
            //1556480
            //140703128616960
            //8
            //17732923532771328
            //65536
            //24576
            //2147483640
            //33776997205278720
            //7881299347898368
            //27021597764222976
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

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

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

        var sb = new System.Text.StringBuilder();
        foreach (string EachStr in InputList.Skip(1)) {
            SplitAct(EachStr);

            long pN = wkArr[0];
            long pX = wkArr[1];
            long pK = wkArr[2];
            long Result = Solve(pN, pX, pK);
            sb.Append(Result);
            sb.AppendLine();
        }
        Console.Write(sb.ToString());
    }

    struct JyoutaiDef
    {
        internal long RangeSta;
        internal long RangeEnd;
        internal long Level;
        internal bool CanUp;
    }

    static long Solve(long pN, long pX, long pK)
    {
        if (pK >= 128) return 0;
        var Stk = new Stack<JyoutaiDef>();
        JyoutaiDef WillPush;
        WillPush.RangeSta = pX;
        WillPush.RangeEnd = pX;
        WillPush.Level = 0;
        WillPush.CanUp = true;

        Stk.Push(WillPush);

        var VisitedSet = new HashSet<long>();
        VisitedSet.Add(pX);

        long Answer = 0;

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

            if (Popped.Level == pK) {
                long Min = Math.Max(1, Popped.RangeSta);
                long Max = Math.Min(pN, Popped.RangeEnd);

                Answer += Max - Min + 1;
                continue;
            }

            // 枝切り
            bool WillEdakiri = false;
            if (Popped.CanUp == false) {
                long RestLevel = pK - Popped.Level;

                long CurrNode = Popped.RangeSta;
                long Beki2 = DeriveBeki2(RestLevel, long.MaxValue);
                if (WillOverProd(Beki2, CurrNode, pN)) {
                    WillEdakiri = true;
                }
            }
            if (WillEdakiri) continue;

            WillPush.RangeSta = Popped.RangeSta * 2;
            if (WillPush.RangeSta <= pN) {
                WillPush.RangeEnd = Popped.RangeEnd * 2 + 1;
                WillPush.Level = Popped.Level + 1;
                WillPush.CanUp = false;

                if (VisitedSet.Contains(WillPush.RangeSta)) {
                    WillPush.RangeSta = WillPush.RangeEnd;
                }
                if (VisitedSet.Contains(WillPush.RangeEnd)) {
                    WillPush.RangeEnd = WillPush.RangeSta;
                }
                if (VisitedSet.Add(WillPush.RangeSta) || VisitedSet.Add(WillPush.RangeEnd)) {
                    Stk.Push(WillPush);
                }
            }

            if (Popped.CanUp) {
                WillPush.RangeSta = Popped.RangeSta / 2;
                if (WillPush.RangeSta >= 1) {
                    if (VisitedSet.Add(WillPush.RangeSta)) {
                        WillPush.RangeEnd = Popped.RangeEnd / 2;
                        WillPush.Level = Popped.Level + 1;
                        WillPush.CanUp = true;
                        Stk.Push(WillPush);
                    }
                }
            }
        }

        return Answer;
    }

    static Dictionary<long, long> mMemo = new Dictionary<long, long>();
    static long DeriveBeki2(long pSisuu, long pLimit)
    {
        if (mMemo.ContainsKey(pSisuu)) {
            return mMemo[pSisuu];
        }

        long WillReturn = 1;
        for (long I = 1; I <= pSisuu; I++) {
            if (WillOverProd(2, WillReturn, long.MaxValue)) {
                break;
            }
            WillReturn *= 2;
        }
        return mMemo[pSisuu] = WillReturn;
    }

    // 2正数の掛け算が、Limitを超えるかを返す
    static bool WillOverProd(long pA, long pB, long pLimit)
    {
        return pA > pLimit / pB;
    }
}


解説

枝切りを見逃さないDFSで、範囲を探索してます。