Ryoku 与最初之人笔记

题目描述

求满足 \(a\equiv b\pmod {a \text{ xor } b}\),且 \(a,b\) 均为小于等于 \(n\) 的非负整数,\(a<b\),的有序二元组 \((a,b)\) 个数。

\(n \leqslant 10^{18}\)

思路点拨

这里提供一种数位dp的做法。

考虑 \(a\equiv b\pmod {a \text{ xor } b}\) 的含义是什么?我们可以将原式理解为:

\[a-k_1(a \oplus b)=b-k_2(a \oplus b) \]

\[(k_2-k_1)(a\oplus b)=b-a \]

由于 \(b-a \leqslant a\oplus b\) 并且 \(k_2-k_1\) 为正整数,所以应该有 \(a\oplus b=b-a\)。这个式子等价于 \(a\&b=a\),其中 \(\&\) 是指位运算中的与。

我们考虑使用数位dp结局这个问题。我们定义 \(dp_{i,j=0/1}\) 表示考虑到二进制位的第 \(i\) 位,目前是否超出了 \(n\) 二进制表示的前 \(j\) 位。转移我们分类讨论:

如果 \(n\&2^i\),那么:

  • \(dp_{i,0}=dp_{i-1,0}\times 3+dp_{i-1,1}\)。因为这一位可以填 \(0,1\),所以对于数字 \(a,b\) 而言,这一数位 \(a,b\) 两数可以使用的组合为 \((0,0),(0,1),(1,1)\)\(dp_{i-1,1}\) 则是代表如果填 \((0,0)\) ,可以消除二进制位的限制。

  • \(dp_{i,1}=dp_{i-1,1}\times 2\) 。为了保持超出二进制位,所以第 \(i\)\(a,b\) 至少有一个填 \(1\) ,组合可以有 \((0,1),(1,1)\)

如果没有满足 \(n \& 2^i\) ,也就是说目前这一位在不超出二进制限制的情况下只可以填 \(0\)

  • \(dp_{i,0}=dp_{i-1,0}\) 。不超出限制只可以填 \((0,0)\)

  • \(dp_{i,1}=dp_{i-1,0}\times 2+dp_{i-1,1}\times 3\) 。可以从 \(dp_{i-1,0}\) 转移是因为可以让 \(a,b\) 在第 \(i\) 位至少填一个 \(1\) 可以使其超出限制,所以可以选择 \((0,1),(1,1)\) ;为什么可以从 \(dp_{i-1,1}\) 转移上面解释过了。

初始化,如果 \(n\) 是奇数,那么 \(dp_{0,0}=3\)

如果 \(n\) 是偶数,那么 \(dp_{0,0}=0,dp_{0,1}=2\)

可能比较抽象,如果不理解可以自己手玩一下。时间复杂度 \(O(\log n)\)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN=64,N=60,mod=1e9+7;
int n,dp[MAXN][2];
signed main(){
	cin>>n;
	if(n&1)
		dp[0][0]=3;
	else dp[0][0]=1,dp[0][1]=2;
	for(int i=1;i<=N;i++){
		if(n&(1ll<<i)){
			dp[i][0]=(dp[i-1][0]*3+dp[i-1][1])%mod;
			dp[i][1]=(dp[i-1][1]*2)%mod;
		}
		else{
			dp[i][0]=dp[i-1][0];
			dp[i][1]=(dp[i-1][0]*2+dp[i-1][1]*3)%mod;
		}
	}
	cout<<(dp[N][0]-(n+1)%mod+mod)%mod;
	return 0;
} 
posted @ 2023-10-20 09:16  Diavolo-Kuang  阅读(6)  评论(0编辑  收藏  举报