[CF1245F]Daniel and Spring Cleaning

Daniel and Spring Cleaning

 

题解

很容易发现,原式等价于\sum_{a=l}^{r}\sum_{b=l}^{r}[a \& b= 0]

再差分一下,\sum^{r}\sum^{r}[a\&b =0]- 2\sum^{l-1}\sum^{r}[a\& b=0]+\sum^{l-1}\sum^{l-1}[a\& b=0]

calc(x,y)= \sum^{x}\sum^{y}[a\& b= 0],接下来,来考虑一下calc函数该怎么求。

由于是二进制,很容易想到数位dp,令dp_{i,j,k}为在转化为二进制后,a的第i位为jb的第i位为k时的满足条件的方案数。

dp的转换也十分好想,判断是否达到上界即可。

源码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
int t,l,r;LL dp[40][2][2];
LL calc(LL a,LL b){
	if(a<0||b<0)return 0;
	memset(dp,0,sizeof(dp));dp[32][1][1]=1;
	for(int i=31;i>=0;i--)
		for(int j=0;j<2;j++)
			for(int k=0;k<2;k++){
				bool nxtj=(j&&!((a>>i)&1LL)),nxtk=(k&&!((b>>i)&1LL));
				dp[i][nxtj][nxtk]+=dp[i+1][j][k];
				if(((a>>i)&1)||!j)dp[i][j][nxtk]+=dp[i+1][j][k];
				if(((b>>i)&1)||!k)dp[i][nxtj][k]+=dp[i+1][j][k];
			}
	return dp[0][0][0]+dp[0][1][0]+dp[0][0][1]+dp[0][1][1];
}
signed main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d %d",&l,&r);l--;
		printf("%lld\n",calc(r,r)-calc(l,r)*2ll+calc(l,l));
	}
	return 0;
}

谢谢!!!

posted @ 2020-08-11 15:06  StaroForgin  阅读(7)  评论(0)    收藏  举报  来源