Ryoku 与最初之人笔记

题目描述

求满足 ab(moda xor b),且 a,b 均为小于等于 n 的非负整数,a<b,的有序二元组 (a,b) 个数。

n1018

思路点拨

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

考虑 ab(moda xor b) 的含义是什么?我们可以将原式理解为:

ak1(ab)=bk2(ab)

(k2k1)(ab)=ba

由于 baab 并且 k2k1 为正整数,所以应该有 ab=ba。这个式子等价于 a&b=a,其中 & 是指位运算中的与。

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

如果 n&2i,那么:

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

  • dpi,1=dpi1,1×2 。为了保持超出二进制位,所以第 ia,b 至少有一个填 1 ,组合可以有 (0,1),(1,1)

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

  • dpi,0=dpi1,0 。不超出限制只可以填 (0,0)

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

初始化,如果 n 是奇数,那么 dp0,0=3

如果 n 是偶数,那么 dp0,0=0,dp0,1=2

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

#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 @   Diavolo-Kuang  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示