D - Masked Popcount
解説
次のように式変形をしていく。
ここで、 は定数から、次が言える。
- もし の bit 目が立っていなければ、常に
- もし の bit 目が立っていなければ
- の bit 目が立っているとき、
- の bit 目が立っていないとき、
また、制約条件から、 の bit 目以降はすべて であることがわかる。
したがって、 に対して、以下を繰り返す。
- の bit 目が立っているとき、 から までの に対して、 bit 目が立っているものの個数を求める
- の bit 目が立っていないときはなにもしない
つまり、問題文は次のように言い換えられる。
以上 以下の整数 に対して、 の bit 目が立っているものの個数を求めよ。
これを に対して求め、その総和を求めることで解ける。
次の事実を用いることで、上の問題を解くことができる。
を非負整数としたとき、 以上 未満の整数のうち、 bit 目が立っているものの個数は、 個
また、次も言える。
を非負整数、 を 未満の整数としたとき、 以上 未満の整数のうち、 bit 目が立っているものの個数は、 個
この二つを合わせて、 以上 未満の整数のうち、 bit 目が立っているものの個数を求めることができる。
提出コード
- Go
const MOD = 998244353
func f(j int, n int) int {
p2 := 1 << uint(j)
k := n / (2 * p2)
res := k * p2
l := n % (2 * p2)
res += max(0, l-p2+1)
return res
}
func main() {
var n, m int
scanIntVariables(&n, &m)
ans := 0
for j := 0; j < 60; j++ {
if 1 & (m>>uint(j)) == 1 {
ans += f(j, n)
ans %= MOD
}
}
writeLine(ans)
}
- C++
#define MOD 998244353
ll f(ll j, ll n) {
ll p2=(1ll<<j);
ll k=n/(2*p2);
ll res=k*p2;
ll l=n%(2*p2);
res += max(0ll, l-p2+1);
return res;
}
int main() {
ll n, m; cin >> n >> m;
ll ans = 0;
rep(j, 0, 60) {
if((m>>j)&1) {
ans += f(j, n);
ans %= MOD;
}
}
cout << ans << endl;
}