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