mini notes

競技プログラミングの解法メモを残していきます。

ABC129 E - Sum Equals Xor (500)

概要

整数Lが与えられる。下記の条件を満たす非負整数の組(a, b)がいくつあるかを求めよ。(mod 10^9+7 して出力)

  • a+b ≦ L
  • a+b = a xor b
制約

1 ≦ L < 2^100001

方針

a + b = a xor b
⇔ a & b = 0
⇔ a, bの2進表記でどちらも1となる桁がない(繰り上がりがない)

下記のような桁DPを作ると見通しがよい。
dp[i][eq]:上からi桁目(1-indexed)まで確定した(a, b)の組数、eq = 1 ならa+b = L、eq = 0ならa+b < L

スタートはdp[0][1] = 1

eqの遷移を見てゆく。
・0 ⇒ 0 の遷移
(a, b)の上の桁がどのようであっても、次の桁は(a, b)= (0, 0), (1, 0), (0, 1)のどれかになる
すなわち dp[i+1][0] += dp[i][0] * 3

・1 ⇒ 0 の遷移
Lの桁が1でなくてはならず、かつ(a, b) = (0, 0)である
すなわち if(L[i] == '1') dp[i+1][0] += dp[i][1]

・1 ⇒ 1 の遷移
Lの桁が0の場合は(a, b) = (0, 0) である
Lの桁が1の場合は(a, b) = (1, 0) , (0, 1)である
すなわち
if(L[i] == '0') dp[i+1][1] += dp[i][1]
if(L[i] == '1') dp[i+1][1] += dp[i][1] * 2

解答

Submission #5862286 - AtCoder Beginner Contest 129

#include <bits/stdc++.h>
#define rep(i,n) for(int i=(0);i<(n);i++)
 
using namespace std;
 
typedef long long ll;
 
ll MOD = 1e9 + 7;
 
int main()
{
	cin.tie(0);
	ios::sync_with_stdio(false);
 
	string L;
	cin >> L;
 
	int n = L.size();
	vector<vector<ll>> dp(n+1, vector<ll>(2, 0));
	dp[0][1] = 1;
 
	for(int i = 0; i < n; i++){
		// 1 -> 1
		if(L[i] == '0'){
			dp[i+1][1] += dp[i][1];
			dp[i+1][1] %= MOD;
		}else{
			dp[i+1][1] += dp[i][1] * 2;
			dp[i+1][1] %= MOD;
		}
 
		// 1 -> 0
		if(L[i] == '1'){
			dp[i+1][0] += dp[i][1];
			dp[i+1][0] %= MOD;
		}
 
		// 0 -> 0
		dp[i+1][0] += dp[i][0] * 3;
		dp[i+1][0] %= MOD;
	}
 
	cout << (dp[n][0] + dp[n][1]) % MOD << endl;
}