AtCoderのABC
次のABCの問題へ
前のABCの問題へ
ABC147-D Xor Sum 4
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("1 2 3");
//6
}
else if (InputPattern == "Input2") {
WillReturn.Add("10");
WillReturn.Add("3 1 4 1 5 9 2 6 5 3");
//237
}
else if (InputPattern == "Input3") {
WillReturn.Add("10");
WillReturn.Add("3 14 159 2653 58979 323846 2643383 27950288 419716939 9375105820");
//103715602
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
const long Hou = 1000000007;
static void Main()
{
List<string> InputList = GetInputList();
long[] AArr = InputList[1].Split(' ').Select(pX => long.Parse(pX)).ToArray();
// 0の個数[2のべき乗]なDict
var Cnt0Dict = new Dictionary<long, long>();
// 1の個数[2のべき乗]
var Cnt1Dict = new Dictionary<long, long>();
foreach (long EachLong in AArr) {
long CurrVal = EachLong;
long Bekijyou = 1;
while (true) {
if (Cnt0Dict.ContainsKey(Bekijyou) == false) Cnt0Dict[Bekijyou] = 0;
if (Cnt1Dict.ContainsKey(Bekijyou) == false) Cnt1Dict[Bekijyou] = 0;
long Mod2 = CurrVal % 2;
if (Mod2 == 0) Cnt0Dict[Bekijyou]++;
if (Mod2 == 1) Cnt1Dict[Bekijyou]++;
if (CurrVal == 0) break;
CurrVal /= 2;
Bekijyou *= 2;
}
}
// 前ゼロの分を補完
foreach (long EachKey in Cnt1Dict.Keys) {
long CntSum = Cnt1Dict[EachKey] + Cnt0Dict[EachKey];
if (CntSum < AArr.Length) {
long Rest = AArr.Length - CntSum;
Cnt0Dict[EachKey] += Rest;
}
}
//foreach (var EachPair in Cnt0Dict) {
// Console.WriteLine("Cnt0Dict[{0}]={1}", EachPair.Key, EachPair.Value);
//}
//foreach (var EachPair in Cnt1Dict) {
// Console.WriteLine("Cnt1Dict[{0}]={1}", EachPair.Key, EachPair.Value);
//}
long Answer = 0;
foreach (var EachPair in Cnt0Dict) {
long CurrVal0 = EachPair.Value;
long CurrVal1 = Cnt1Dict[EachPair.Key];
long CurrKetaSum = EachPair.Key % Hou;
CurrKetaSum *= (CurrVal0 * CurrVal1) % Hou;
CurrKetaSum %= Hou;
Answer += CurrKetaSum;
Answer %= Hou;
}
Console.WriteLine(Answer);
}
}
解説
排他的論理和なのでビットごとに考えることができます。
1 2 3 4 5 6 7
というサンプルで考え、2進数で表すと
001
010
011
100
101
110
111
となります。
1ビット目に注目すると
全部で 7*6/2 = 210 通りの 0と1の組み合わせの中で
排他的論理和の結果が1になるのは、片方が0で片方が1になるペアなので
0の数が3で、1の数が4なので
3*4 = 12 通りの 排他的論理和が1になる組み合わせがあります。
他のビットも同様にして、
全ての組み合わせの排他的論理和の総和を求めることができます。