AtCoderのABC
次のABCの問題へ
前のABCの問題へ
ABC374-E Sensor Optimization Dilemma 2
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("3 22");
WillReturn.Add("2 5 3 6");
WillReturn.Add("1 1 3 3");
WillReturn.Add("1 3 2 4");
//4
}
else if (InputPattern == "Input2") {
WillReturn.Add("1 10000000");
WillReturn.Add("100 1 100 1");
//1000000000
}
else if (InputPattern == "Input3") {
WillReturn.Add("1 1");
WillReturn.Add("1 10000000 1 10000000");
//0
}
else if (InputPattern == "Input4") {
WillReturn.Add("10 7654321");
WillReturn.Add("8 6 9 1");
WillReturn.Add("5 6 4 3");
WillReturn.Add("2 4 7 9");
WillReturn.Add("7 8 9 1");
WillReturn.Add("7 9 1 6");
WillReturn.Add("4 8 9 1");
WillReturn.Add("2 2 8 9");
WillReturn.Add("1 6 2 6");
WillReturn.Add("4 2 3 4");
WillReturn.Add("6 6 5 2");
//894742
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
static long mX;
struct ItemInfoDef
{
internal long A;
internal long P;
internal long B;
internal long Q;
}
static List<ItemInfoDef> mItemInfoList = new List<ItemInfoDef>();
static void Main()
{
List<string> InputList = GetInputList();
long[] wkArr = { };
Action<string> SplitAct = pStr =>
wkArr = pStr.Split(' ').Select(pX => long.Parse(pX)).ToArray();
SplitAct(InputList[0]);
mX = wkArr[1];
foreach (string EachStr in InputList.Skip(1)) {
SplitAct(EachStr);
ItemInfoDef WillAdd;
WillAdd.A = wkArr[0];
WillAdd.P = wkArr[1];
WillAdd.B = wkArr[2];
WillAdd.Q = wkArr[3];
mItemInfoList.Add(WillAdd);
}
long L = 0;
long R = mX * 100;
if (CanAchieve(R)) {
Console.WriteLine(R);
return;
}
while (L + 1 < R) {
long Mid = (L + R) / 2;
if (CanAchieve(Mid)) {
L = Mid;
}
else {
R = Mid;
}
}
Console.WriteLine(L);
}
// 工程を全てK以上にできるかを返す
static bool CanAchieve(long pK)
{
long RestX = mX;
foreach (ItemInfoDef EachItemInfo in mItemInfoList) {
RestX -= DeriveCost(pK, EachItemInfo);
if (RestX < 0) return false;
}
return RestX >= 0;
}
// K作るのにかかる最小コストを返す
static long DeriveCost(long pK, ItemInfoDef pItemInfo)
{
long A = pItemInfo.A;
long B = pItemInfo.B;
long P = pItemInfo.P;
long Q = pItemInfo.Q;
long LCM = DeriveLCM2(A, B);
long LCM_Cost = Math.Min(LCM / A * P, LCM / B * Q);
var CostList = new List<long>();
for (long I = 0; I <= LCM / A; I++) {
long Cost = I * P;
long Rest = pK - A * I;
if (Rest <= 0) {
CostList.Add(Cost);
break;
}
for (long J = 0; J <= LCM / B; J++) {
long NewCost = Cost + J * Q;
long NewRest = Rest - B * J;
if (NewRest <= 0) {
CostList.Add(NewCost);
break;
}
// 残りは、LCMを使う
long Div = NewRest / LCM;
NewCost += Div * LCM_Cost;
if (NewRest % LCM > 0) {
NewCost += LCM_Cost;
}
CostList.Add(NewCost);
}
}
return CostList.Min();
}
// 2つの数のLCMを求める
static long DeriveLCM2(long p1, long p2)
{
long GCD = DeriveGCD(p1, p2);
return (p1 / GCD) * p2;
}
// ユークリッドの互除法で2数の最大公約数を求める
static long DeriveGCD(long pVal1, long pVal2)
{
long WarareruKazu = pVal2;
long WaruKazu = pVal1;
while (true) {
long Amari = WarareruKazu % WaruKazu;
if (Amari == 0) return WaruKazu;
WarareruKazu = WaruKazu;
WaruKazu = Amari;
}
}
}
解説
3gで100円
7gで130円
30g以上作るのに最低何円かかるか?
という問題は、
LCM以下の3の倍数 {0,3,6,9,12,15,18}
LCM以下の7の倍数 {0,7,14,21}
の組み合わせを全探索し、
残りがあったら、それはLCMを使うことにして、
これは、割り算すれば高速に解けます。