トップページに戻る
次の競技プログラミングの問題へ
前の競技プログラミングの問題へ
ABC-118-D Match Matching
■■■問題■■■
ちょうどN本のマッチ棒を使って作れる整数の中で最大のものを求めてください。
ただし、以下の条件を満たさなければなりません。
●作る整数の各桁は、1から9までの数字のうち A1 , A2 , ・・・ , AM (1<=Ai<=9) のいずれかでなければならない。
●数字 1,2,3,4,5,6,7,8,9を1つ作るには、それぞれちょうど 2,5,5,4,5,6,3,7,6本のマッチ棒を使う。
■■■入力■■■
N M
A1 A2 ・・・ AN
●入力は全て整数である
●2 <= N <= 1万
●1 <= M <= 9
●1 <= Ai <= 9
●Aiは全て異なる
●ちょうどN本のマッチ棒を使って条件を満たすように作れる整数が存在する
■■■出力■■■
問題文の条件下でちょうどN本のマッチ棒を使って作れる整数の最大値を出力せよ。
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("20 4");
WillReturn.Add("3 7 8 4");
//777773
//整数777773は 3+3+3+3+3+5 = 20 本のマッチ棒を使って作れ、
//ちょうど20本のマッチ棒を使って条件を満たすように作れる整数の中でこれが最大です
}
else if (InputPattern == "Input2") {
WillReturn.Add("101 9");
WillReturn.Add("9 8 7 6 5 4 3 2 1");
//71111111111111111111111111111111111111111111111111
//出力が64ビット整数型に収まらない場合があります
}
else if (InputPattern == "Input3") {
WillReturn.Add("15 3");
WillReturn.Add("5 4 6");
//654
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
static void Main()
{
List<string> InputList = GetInputList();
int[] wkArr = InputList[0].Split(' ').Select(X => int.Parse(X)).ToArray();
int N = wkArr[0];
int[] AArr = InputList[1].Split(' ').Select(X => int.Parse(X)).ToArray();
var CostDict = new Dictionary<int, int>();
if (AArr.Contains(1)) CostDict.Add(1, 2);
if (AArr.Contains(2)) CostDict.Add(2, 5);
if (AArr.Contains(3)) CostDict.Add(3, 5);
if (AArr.Contains(4)) CostDict.Add(4, 4);
if (AArr.Contains(5)) CostDict.Add(5, 5);
if (AArr.Contains(6)) CostDict.Add(6, 6);
if (AArr.Contains(7)) CostDict.Add(7, 3);
if (AArr.Contains(8)) CostDict.Add(8, 7);
if (AArr.Contains(9)) CostDict.Add(9, 6);
if (CostDict.ContainsKey(1)) CostDict.Remove(4);
if (CostDict.ContainsKey(1)) CostDict.Remove(6);
if (CostDict.ContainsKey(1)) CostDict.Remove(9);
if (CostDict.ContainsKey(3)) CostDict.Remove(2);
if (CostDict.ContainsKey(5)) CostDict.Remove(2);
if (CostDict.ContainsKey(5)) CostDict.Remove(3);
if (CostDict.ContainsKey(7)) CostDict.Remove(6);
if (CostDict.ContainsKey(7)) CostDict.Remove(9);
if (CostDict.ContainsKey(9)) CostDict.Remove(6);
if (CostDict.ContainsKey(1) && CostDict.ContainsKey(2)) CostDict.Remove(8);
if (CostDict.ContainsKey(1) && CostDict.ContainsKey(3)) CostDict.Remove(8);
if (CostDict.ContainsKey(1) && CostDict.ContainsKey(5)) CostDict.Remove(8);
if (CostDict.ContainsKey(1) && CostDict.ContainsKey(4)) CostDict.Remove(6);
if (CostDict.ContainsKey(1) && CostDict.ContainsKey(4)) CostDict.Remove(9);
if (CostDict.ContainsKey(1) && CostDict.ContainsKey(7)) {
CostDict.Remove(2);
CostDict.Remove(3);
CostDict.Remove(4);
CostDict.Remove(5);
CostDict.Remove(6);
CostDict.Remove(8);
CostDict.Remove(9);
}
if (CostDict.ContainsKey(4) && CostDict.ContainsKey(7)) CostDict.Remove(8);
int[] SortedKeysArr = CostDict.Keys.OrderByDescending(X => X).ToArray();
//最大の数字[使用する文字数]なDP表
int UB = N;
string[] DPArr = new string[UB + 1];
for (int I = 0; I <= UB; I++)
DPArr[I] = "";
for (int I = 0; I <= SortedKeysArr.GetUpperBound(0); I++) {
for (int J = 0; J <= UB; J++) {
if (J > 0 && DPArr[J] == "") continue;
int NewJ = J + CostDict[SortedKeysArr[I]];
if (NewJ > UB) continue;
string NewVal = DPArr[J] + SortedKeysArr[I].ToString();
if (StringComp(NewVal, DPArr[NewJ]) == -1) continue;
DPArr[NewJ] = NewVal;
}
}
Console.WriteLine(DPArr[UB]);
}
//文字列を数値として比較した結果を返す
//p1のほうが大きければ1
//p2のほうが大きければ-1
//p1とp2が等しければ0
static int StringComp(string p1, string p2)
{
if (p1.Length < p2.Length) return -1;
if (p1.Length > p2.Length) return 1;
return p1.CompareTo(p2);
}
}
解説
配るDPで解いてます。