AtCoderのABC
次のABCの問題へ
前のABCの問題へ
ABC281-F Xor Minimization
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");
WillReturn.Add("12 18 11");
//16
}
else if (InputPattern == "Input2") {
WillReturn.Add("10");
WillReturn.Add("0 0 0 0 0 0 0 0 0 0");
//0
}
else if (InputPattern == "Input3") {
WillReturn.Add("5");
WillReturn.Add("324097321 555675086 304655177 991244276 9980291");
//805306368
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
static long[] GetSplitArr(string pStr)
{
return (pStr == "" ? new string[0] : pStr.Split(' ')).Select(pX => long.Parse(pX)).ToArray();
}
static void Main()
{
List<string> InputList = GetInputList();
long[] AArr = GetSplitArr(InputList[1]);
if (Array.TrueForAll(AArr, pX => pX == 0)) {
Console.WriteLine(0);
return;
}
Array.Sort(AArr);
long MaxA = AArr.Max();
long CurrBeki2 = 1;
while (true) {
if (CurrBeki2 * 2 < MaxA) {
CurrBeki2 *= 2;
}
else {
break;
}
}
// 2べき値[レベル]なDcit
var Beki2Dict = new Dictionary<long, long>();
for (long I = 1; I < long.MaxValue; I++) {
Beki2Dict[I] = CurrBeki2;
CurrBeki2 /= 2;
if (CurrBeki2 == 0) break;
}
long LevelLimit = Beki2Dict.Keys.Max();
var Stk = new Stack<JyoutaiDef>();
JyoutaiDef WillPush;
WillPush.KouhoIndSta = 0;
WillPush.KouhoIndEnd = AArr.GetUpperBound(0);
WillPush.Level = 0;
WillPush.CurrVal = 0;
Stk.Push(WillPush);
long Answer = long.MaxValue;
while (Stk.Count > 0) {
JyoutaiDef Popped = Stk.Pop();
if (Popped.Level == LevelLimit) {
long CurrMax = long.MinValue;
for (long I = Popped.KouhoIndSta; I <= Popped.KouhoIndEnd; I++) {
CurrMax = Math.Max(CurrMax, AArr[I] ^ Popped.CurrVal);
}
Answer = Math.Min(Answer, CurrMax);
continue;
}
long NextLevel = Popped.Level + 1;
long CurrBit = Beki2Dict[NextLevel];
// ビットが2通りあるかを調べる
var AppearBitSet = new HashSet<long>();
for (long I = Popped.KouhoIndSta; I <= Popped.KouhoIndEnd; I++) {
AppearBitSet.Add(AArr[I] & CurrBit);
}
if (AppearBitSet.Count == 1) {
WillPush.KouhoIndSta = Popped.KouhoIndSta;
WillPush.KouhoIndEnd = Popped.KouhoIndEnd;
WillPush.Level = Popped.Level + 1;
if (AppearBitSet.Max() == 0) {
WillPush.CurrVal = Popped.CurrVal;
}
else {
WillPush.CurrVal = Popped.CurrVal + CurrBit;
}
Stk.Push(WillPush);
continue;
}
// このビットを0にする場合
var IndList0 = new List<long>();
for (long I = Popped.KouhoIndSta; I <= Popped.KouhoIndEnd; I++) {
if ((AArr[I] & CurrBit) > 0) {
IndList0.Add(I);
}
}
if (IndList0.Count > 0) {
WillPush.KouhoIndSta = IndList0.Min();
WillPush.KouhoIndEnd = IndList0.Max();
WillPush.Level = Popped.Level + 1;
WillPush.CurrVal = Popped.CurrVal;
Stk.Push(WillPush);
}
// このビットを1にする場合
var IndList1 = new List<long>();
for (long I = Popped.KouhoIndSta; I <= Popped.KouhoIndEnd; I++) {
if ((AArr[I] & CurrBit) == 0) {
IndList1.Add(I);
}
}
if (IndList1.Count > 0) {
WillPush.KouhoIndSta = IndList1.Min();
WillPush.KouhoIndEnd = IndList1.Max();
WillPush.Level = Popped.Level + 1;
WillPush.CurrVal = Popped.CurrVal + CurrBit;
Stk.Push(WillPush);
}
}
Console.WriteLine(Answer);
}
struct JyoutaiDef
{
internal long KouhoIndSta;
internal long KouhoIndEnd;
internal long Level;
internal long CurrVal;
}
}
解説
まず対象の数列を昇順にソートします。
上位桁から桁ごとに見ていき、
その桁に0と1が混在するなら、両方を試す。
混在しないなら、そり小さくできるビットを採用する。
という方針でDFSで解いてます。