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

B57 Calculator


問題へのリンク


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("10 1");
            //0
            //0
            //0
            //0
            //0
            //0
            //0
            //0
            //0
            //9
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

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

        long UB = N;

        // 現在の値[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] = I - DeriveKetaSum(I);
        }

        // 2べき回の変換後の値を設定
        long Beki2 = 2;
        while (Beki2 <= K) {
            long Div2 = Beki2 / 2;
            for (long I = 0; I <= UB; I++) {
                long Div2Val = DoublingDictArr[I][Div2];
                long GoalVal = DoublingDictArr[Div2Val][Div2];
                DoublingDictArr[I][Beki2] = GoalVal;
            }
            Beki2 *= 2;
        }

        // 解を求める
        var sb = new System.Text.StringBuilder();
        for (long I = 1; I <= UB; I++) {
            long CurrVal = I;
            long RestCnt = K;

            while (RestCnt > 0) {
                long MaxBeki2 = DeriveMaxBeki2(RestCnt);
                CurrVal = DoublingDictArr[CurrVal][MaxBeki2];
                RestCnt -= MaxBeki2;
            }
            sb.Append(CurrVal);
            sb.AppendLine();
        }
        Console.Write(sb.ToString());
    }

    // 数値を引数として、桁和を返す
    static long DeriveKetaSum(long pTarget)
    {
        long WillReturn = 0;
        while (pTarget > 0) {
            WillReturn += pTarget % 10;
            pTarget /= 10;
        }
        return WillReturn;
    }

    // 引数の数値以下で、最大の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;
    }
}


解説

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