题目链接:https://ac.nowcoder.com/acm/contest/887/H
题意:给定A,B,C问在[1,A]和[1,B]中有多少对x,y满足x&y>C或者x^y<C.
数据范围:1<=A,B,C<=1e9
思路:数位dp,定义一个dp[len][lim1][lim2][ok1][ok2][za][zb]。len代表当前枚举的二进制位,lim1,lim2分别代表x和y的上限,ok1代表对于x&y>C是否成立,成立是1,有可能成立是0,不可能成立是-1,ok2代表对于x^y<C是否成立,1代表不成立,0代表可能成立,-1代表成立,za和zb分别代表x和y的数中是否出现了1,因为x和y的二进制位不能是全零。转移的话代码中非常容易看懂。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t;
ll A,B,C,f[50],g[50],h[50];
ll dp[66][2][2][3][3][2][2];
ll dfs(ll len,ll lim1,ll lim2,ll ok1,ll ok2,ll za,ll zb){
ll &ret=dp[len][lim1][lim2][ok1+1][ok2+1][za][zb];
if(ret!=-1)return ret;
if(len==0){
ret=za&&zb&&(ok1>0||ok2<0);
return ret;
}
ret=0; --len;
int up1=lim1?1:f[len];
int up2=lim2?1:g[len];
for(int x=0;x<=up1;x++)for(int y=0;y<=up2;y++)
ret+=dfs(len,lim1|(x<f[len]),lim2|(y<g[len]),ok1==0?(x&y)-h[len]:ok1,ok2==0?(x^y)-h[len]:ok2,za|x,zb|y);
return ret;
}
int main(){
scanf("%d",&t);
while(t--){
memset(dp,-1,sizeof(dp));
scanf("%lld%lld%lld",&A,&B,&C);
for(int i=0;i<30;i++){
f[i]=A%2,A/=2;
g[i]=B%2,B/=2;
h[i]=C%2,C/=2;
}
printf("%lld\n",dfs(31,0,0,0,0,0,0));
}
return 0;
}