题目传送门
题意
给你 T ( 1 ≤ T ≤ 100 ) T(1\le T \le 100) T(1≤T≤100)组询问,每次询问四个数 A , B , C , X ( 1 ≤ A , B , C , X ≤ 1 0 18 A,B,C,X(1\le A,B,C,X\le 10^{18} A,B,C,X(1≤A,B,C,X≤1018,问你有多少个三元组 ( a , b , c ) (a,b,c) (a,b,c)满足 a a a xor b ≤ X b\le X b≤X, a a a xor c ≤ X c\le X c≤X, b b b xor c ≤ X c\le X c≤X。
思路
这个数据范围很容易想到数位dp,要是加上下限,问你三个小区间内有多少就更像数位dp了。
我们用 f [ p o s ] [ l a ] [ l b ] [ l c ] [ l a b ] [ l a c ] [ l b c ] f[pos][la][lb][lc][lab][lac][lbc] f[pos][la][lb][lc][lab][lac][lbc]表示状态数组, p o s pos pos表示当前搜到了第 p o s pos pos位, l a , l b , l c la,lb,lc la,lb,lc分别表示当前搜索到的 a , b , c a,b,c a,b,c是否被 A , B , C A,B,C A,B,C限制, l a b , l a c , l b c lab,lac,lbc lab,lac,lbc则表示 a a a xor b b b, a a a xor c c c, b b b xor c c c是否被 X X X限制。然后套模板就行了。
C o d e Code Code
// Author : ACfunhsl
// Time : 2021/5/22 16:42:57
#define int long long
const int N = 1e6+50;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
int aa[N],bb[N],cc[N],xx[N],cnta,cntb,cntc,cntx;
int f[100][2][2][2][2][2][2];
int dfs(int pos,int la,int lb,int lc,int lab,int lac,int lbc)
{
if(pos==-1) return 1;
int &ans = f[pos][la][lb][lc][lab][lac][lbc];
if(ans!=-1) return ans;
ans = 0;
int upa = la?aa[pos]:1;
int upb = lb?bb[pos]:1;
int upc = lc?cc[pos]:1;
int upx = xx[pos];
for(int i=0;i<=upa;i++)
{
for(int j=0;j<=upb;j++)
{
for(int k=0;k<=upc;k++)
{
if(lab && (i^j)>upx) continue;
if(lac && (i^k)>upx) continue;
if(lbc && (j^k)>upx) continue;
ans = (ans + dfs(pos-1,la&&(i==upa),lb&&(j==upb),lc&&(k==upc),lab&&(i^j==upx),lac&&(i^k==upx),lbc&&(j^k==upx))%mod)%mod;
}
}
}
return ans;
}
int solve(int a,int b,int c,int x)
{
cnta = cntb = cntc = cntx = 0;
mem(aa,0);
mem(bb,0);
mem(cc,0);
mem(xx,0);
while(a)
aa[cnta++] = a&1,a>>=1;
while(b)
bb[cntb++] = b&1,b>>=1;
while(c)
cc[cntc++] = c&1,c>>=1;
while(x)
xx[cntx++] = x&1,x>>=1;
return dfs(63,1,1,1,1,1,1);
}
signed main()
{
int t;
cin>>t;
while(t--)
{
int a,b,c,x;
cin>>a>>b>>c>>x;
memset(f,-1,sizeof f);
cout<<solve(a,b,c,x)<<endl;
}
return 0;
}