Codeforces 1245F. Daniel and Spring Cleaning(容斥原理+数位DP)

传送门

题目大意#

给你两个数,\(l,r\)\([l,r]\) 中多少对 \(a+b=a\oplus b\)

思路#

看了大佬的题解才知道这里要用到二维容斥。
\(f_{x,y}\)\(a\in [0,x],b\in [0,y]\) 时满足条件的对数
那么根据容斥原理答案就是 \(f_{r,r}-f_{l-1,r}\times 2+f_{l-1,l-1}\)
对于其中每一部分都可以用一次数位DP求出来
因为这里对于统计有影响的因素只有两个数是否被限制
那么状态可以直接设计为 \(dp_{pos,lim1,lim2}\)
代表在 \(pos\)\(a,b\) 是否被限制时的个数。

代码#

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
using namespace std;
typedef long long LL;
int T,a[70],b[70];
LL f[70][2][2];

LL dfs(int pos,int lim1,int lim2){
	if(pos==-1) return 1;
	if(f[pos][lim1][lim2]!=-1) return f[pos][lim1][lim2];
	LL temp=0;
	int up1=lim1?a[pos]:1,up2=lim2?b[pos]:1;
	for(int i=0;i<=up1;i++)
		for(int j=0;j<=up2;j++){
			if(i==1&&j==1) continue;
			temp+=dfs(pos-1,lim1&&i==a[pos],lim2&&j==b[pos]);
		}
	f[pos][lim1][lim2]=temp;
	return temp;
}

LL solve(int x,int y){
	memset(f,-1,sizeof(f));
	int pos;
	for(pos=0;x||y;pos++,x/=2,y/=2)
		a[pos]=x%2,b[pos]=y%2;
	return dfs(pos-1,1,1);
}

int main(){
	scanf("%d",&T);
	int l,r;
	memset(f,-1,sizeof(f));
	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;
}
posted @ 2019-11-10 01:02  BakaCirno  阅读(323)  评论(0编辑  收藏  举报