AOJ本の読書メモ
AOJ
次のAOJの問題へ
前のAOJの問題へ
AOJ 0529 ダーツ
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("4 50");
WillReturn.Add("3");
WillReturn.Add("14");
WillReturn.Add("15");
WillReturn.Add("9");
WillReturn.Add("3 21");
WillReturn.Add("16");
WillReturn.Add("11");
WillReturn.Add("2");
WillReturn.Add("0 0");
//48
//20
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
struct InputInfoDef
{
internal int M;
internal int[] PArr;
}
static List<InputInfoDef> mInputInfoList = new List<InputInfoDef>();
static void Main()
{
List<string> InputList = GetInputList();
bool IsReadArr = false;
var PList = new List<int>();
int RestN = -1;
InputInfoDef WillAdd = new InputInfoDef();
foreach (string EachStr in InputList) {
if (IsReadArr == false) {
int[] wkArr = EachStr.Split(' ').Select(pX => int.Parse(pX)).ToArray();
int N = wkArr[0];
int M = wkArr[1];
if (N == 0 && M == 0) break;
WillAdd.M = M;
RestN = N;
IsReadArr = true;
PList.Clear();
}
else {
PList.Add(int.Parse(EachStr));
if (--RestN == 0) {
WillAdd.PArr = PList.ToArray();
mInputInfoList.Add(WillAdd);
IsReadArr = false;
}
}
}
foreach (InputInfoDef EachInputInfo in mInputInfoList) {
Solve(EachInputInfo.M, EachInputInfo.PArr);
}
}
static void Solve(int pM, int[] pPArr)
{
// 2個以下の組み合わせを全探索
var SumSet = new HashSet<long>();
for (int I = 0; I <= pPArr.GetUpperBound(0); I++) {
SumSet.Add(pPArr[I]);
for (int J = 0; J <= pPArr.GetUpperBound(0); J++) {
SumSet.Add(pPArr[I] + pPArr[J]);
}
}
long[] SumArr = SumSet.ToArray();
Array.Sort(SumArr);
long Answer = 0;
foreach (long EachLong in SumArr) {
if (EachLong <= pM) {
Answer = Math.Max(Answer, EachLong);
}
}
// 二分法で最適値を取得して、解候補とする
foreach (long EachSum in SumArr) {
long RestVal = pM - EachSum;
int ResultInd = ExecNibunhou(RestVal, SumArr);
if (ResultInd == -1) break;
long AnswerKouho = EachSum + SumArr[ResultInd];
Answer = Math.Max(Answer, AnswerKouho);
}
Console.WriteLine(Answer);
}
// 二分法で、引数以下で最大の値を持つ、添字を返す
static int ExecNibunhou(long pRest, long[] pArr)
{
// 最後の要素がRest以下の特殊ケース
if (pRest >= pArr.Last()) {
return pArr.GetUpperBound(0);
}
// 最初の要素がRest未満の特殊ケース
if (pRest < pArr[0]) {
return -1;
}
int L = 0;
int R = pArr.GetUpperBound(0);
while (L + 1 < R) {
int Mid = (L + R) / 2;
if (pArr[Mid] <= pRest) {
L = Mid;
}
else {
R = Mid;
}
}
return L;
}
}
解説
全部で4個のダーツを投げるので、
半分全探索として、
2個のダーツの重複組み合わせを全探索し、
残りの2個のダーツの重複組み合わせの最適解の取得では、二分法を使ってます。