トップページに戻る    次の競技プログラミングの問題へ    前の競技プログラミングの問題へ

ARC-050-B 花束

■■■問題■■■

高橋君は赤い花をR本、青い花をB本持っています。
高橋君は次の2種類の花束を作ることができます。

●x本の赤い花と1本の青い花からなる花束
●1本の赤い花とy本の青い花からなる花束

高橋君が作ることのできる花束の個数の最大値を求めてください。
すべての花を使い切る必要はありません。

■■■入力■■■

R B
x y

●1 <= R,B <= 10の18乗
●2 <= x,y <= 10億

■■■出力■■■

高橋君が作ることのできる花束の個数の最大値を出力せよ。


C#のソース

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static string InputPattern = "Input1";

    static List<string> GetInputList()
    {
        var WillReturn = new List<string>();

        if (InputPattern == "Input1") {
            WillReturn.Add("5 5");
            WillReturn.Add("3 4");
            //2
            //「3本の赤い花と1本の青い花からなる花束」を1個と、
            //「1本の赤い花と4本の青い花からなる花束」を1個作ればよいです。
            //このとき、赤い花が1本余ります。
        }
        else if (InputPattern == "Input2") {
            WillReturn.Add("10 20");
            WillReturn.Add("2 2");
            //10
            //「1本の赤い花と2本の青い花からなる花束」を10個作ればよいです
        }
        else if (InputPattern == "Input3") {
            WillReturn.Add("1 1");
            WillReturn.Add("2 2");
            //0
        }
        else if (InputPattern == "Input4") {
            WillReturn.Add("10000000000 10000000000");
            WillReturn.Add("4 3");
            //4545454545
            //入力値および出力値は32bit整数型に収まらない場合があります
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

    static long mR;
    static long mB;
    static long mX;
    static long mY;

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

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

        SplitAct(InputList[0]);
        mR = wkArr[0]; mB = wkArr[1];

        SplitAct(InputList[1]);
        mX = wkArr[0]; mY = wkArr[1];

        Console.WriteLine(ExecNibunHou());
    }

    //2分法で最大で何個の花束を作れるかを調べる
    static long ExecNibunHou()
    {
        long L = 0;
        long R = Math.Min(mR, mB) + 1;

        while (L + 1 < R) {
            long Mid = (L + R) / 2;

            bool CanCreate = DeriveCanCreate(Mid);
            if (CanCreate) L = Mid;
            else R = Mid;
        }
        return L;
    }

    //K個の花束を作れるかを返す
    static bool DeriveCanCreate(long pK)
    {
        long RestR = mR, RestB = mB;

        //両方の花束で共通使用する赤1本と青1本を、先に分配する
        RestR -= pK;
        RestB -= pK;

        long CanCreateCnt = 0;

        //残った赤色のバラで作れる花束
        CanCreateCnt += RestR / (mX - 1);

        //残った青色のバラで作れる花束
        CanCreateCnt += RestB / (mY - 1);

        return pK <= CanCreateCnt;
    }
}


解説

K個の花束が作成可能かの判定は、
両方の花束で共通使用する赤1本と青1本を、先に分配すれば、
貪欲法を使うことができます。

ABC-063-D Widespread