AtCoderのABC
次のABCの問題へ
前のABCの問題へ
ABC356-D Masked Popcount
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 3");
//4
}
else if (InputPattern == "Input2") {
WillReturn.Add("0 0");
//0
}
else if (InputPattern == "Input3") {
WillReturn.Add("1152921504606846975 1152921504606846975");
//499791890
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
// ビット値[ビット位置]
static Dictionary<long, long> mBitValDict = new Dictionary<long, long>();
const long Hou = 998244353;
static void Main()
{
List<string> InputList = GetInputList();
long[] wkArr = InputList[0].Split(' ').Select(pX => long.Parse(pX)).ToArray();
long N = wkArr[0];
long M = wkArr[1];
long CurrVal = 1;
for (long I = 1; I <= 62; I++) {
mBitValDict[I] = CurrVal;
CurrVal *= 2;
}
long Answer = 0;
Dictionary<long, long> ResultDict0 = DeriveZeroCnt(N);
foreach (var EachPair in ResultDict0) {
long ZeroCnt = EachPair.Value;
long OneCnt = (N + 1) - EachPair.Value;
OneCnt %= Hou;
if ((M & EachPair.Key) > 0) {
Answer += OneCnt;
Answer %= Hou;
}
}
if (Answer < 0) {
Answer += Hou;
}
Console.WriteLine(Answer);
}
// Nを引数とし、0からNまでの2進数表現での、0の個数を返す
static Dictionary<long, long> DeriveZeroCnt(long pVal)
{
var WillReturn = new Dictionary<long, long>();
foreach (var EachPair in mBitValDict) {
long Cycle = pVal / (EachPair.Value * 2);
long Cnt1 = Cycle * EachPair.Value;
Cnt1 %= Hou;
long Rest = pVal + 1 - Cycle * (EachPair.Value * 2);
long Cnt2 = Math.Min(Rest, EachPair.Value);
Cnt2 %= Hou;
WillReturn[EachPair.Value] = Cnt1 + Cnt2;
WillReturn[EachPair.Value] %= Hou;
}
return WillReturn;
}
}
解説
ビット論理積とPopCountなので
ビットごとに独立で考えることができます。
Nを引数として、
0からNまでの
ビットごとの0の数を求めるメソッドを作成すれば解く事ができます。
8 4 2 1
0 0 0 0
0 0 0 1
0 0 1 0
0 0 1 1
0 1 0 0
0 1 0 1
0 1 1 0
0 1 1 1
1 0 0 0
1 0 0 1
1 0 1 0
1 0 1 1
1 1 0 0
1 1 0 1
1 1 1 0
1 1 1 1