Codeforce 1245 F. Daniel and Spring Cleaning(数位 dp + 容斥)

题目大意:在 [l,r] 区间内,找出所有的数字对 (x,y),使得 x + y = x ^ y

首先x + y = x ^ y 等价于 x & y = 0

s o l v e ( l , r ) solve(l,r) solve(l,r) 解决的 一个数字的范围是 [1,l],另一个数字的范围是 [1,r]。

答案可以容斥得到: s o l v e ( r , r ) − 2 ∗ s o l v e ( l − 1 , r ) + s o l v e ( l − 1 , l − 1 ) solve(r,r) - 2 * solve(l - 1,r) + solve(l - 1,l - 1) solve(r,r)2solve(l1,r)+solve(l1,l1)

对于 s o l v e ( l , r ) solve(l,r) solve(l,r),可以按二进制位进行 dp,只需要满足一个数小于等于 l,另一个数小于等于 r 的限制即可。这个限制在数位 dp 里很容易实现


代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e2 + 10;
typedef long long ll;
int t,l,r;
int L,R;
ll dp[maxn][2][2];
ll dfs(int cur,int limit_l,int limit_r) {
	if(cur < 0) return 1;
	if(dp[cur][limit_l][limit_r] != -1) return dp[cur][limit_l][limit_r];
	ll &ans = dp[cur][limit_l][limit_r] = 0;
	int up_l = limit_l ? (L >> cur) & 1 : 1;
	int up_r = limit_r ? (R >> cur) & 1 : 1;
	for(int i = 0; i <= up_l; i++)
		for(int j = 0; j <= up_r; j++)
			if(!(i & j))
				ans += dfs(cur - 1,limit_l && i == up_l,limit_r && j == up_r);
	return ans;
}
ll solve(int l,int r) {
	if(l < 0 || r < 0) return 0;
	L = l,R = r;
	memset(dp,-1,sizeof dp);
	return dfs(30,1,1);
}
int main() {
	scanf("%d",&t);
	while(t--) {
		scanf("%d%d",&l,&r);
		printf("%lld\n",solve(r,r) - 2 * solve(l - 1,r) + solve(l - 1,l - 1));
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值