题解
数位DP似乎正解是找i^j的龟绿
在二进制上做数位\(DP\),需要同时满足\(n,m,k\)三个限制条件
那么设\(f[i][0/1][0/1][0/1]\)表示当前到从前往后的第i位,到这一位的位置时是否卡\(n\)上界,是否卡\(m\)的上界,是否卡\(k\)的下界的异或和,\(g[i][0/1][0/1][0/1]\)表示方案数
因为如果异或和小于k就变成0了,那么我们只需要考虑异或和\(>=k\)的数,然后最后再把\(f[]\)的答案减去\(k*g[]\)
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
# define int long long
const int M = 75 ;
using namespace std ;
inline int read() {
char c = getchar() ; int x = 0 , w = 1 ;
while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
return x*w ;
}
bool wn[M] , wm[M] , wk[M] ;
int n , m , k , mod , len ;
int f[M][2][2][2] , g[M][2][2][2] , ans ;
void dfs(int pos , bool upn , bool upm , bool kp) {
// 当前位数,是否卡n的上界,是否卡m的上界,是否卡k的下界
if(g[pos][upn][upm][kp]) return ;
if(pos > len) {
f[pos][upn][upm][kp] = 0 ;
g[pos][upn][upm][kp] = 1 ;
return ;
}
int ret1 , ret2 , rn = (upn ? wn[pos] : 1) ,
rm = (upm ? wm[pos] : 1) , kw = wk[pos] ;
for(int i = 0 ; i <= rn ; i ++)
for(int j = 0 ; j <= rm ; j ++) {
if(kp && ((i ^ j) < kw)) continue ;
dfs(pos + 1 , (upn & (i == rn)) , (upm & (j == rm)) , (kp & ((i ^ j) == kw))) ;
ret1 = g[pos + 1][(upn & (i == rn))][(upm & (j == rm))][(kp & ((i ^ j) == kw))] % mod ;
ret2 = f[pos + 1][(upn & (i == rn))][(upm & (j == rm))][(kp & ((i ^ j) == kw))] % mod ;
g[pos][upn][upm][kp] = (g[pos][upn][upm][kp] + ret1) % mod ;
f[pos][upn][upm][kp] = (f[pos][upn][upm][kp] + ((i ^ j) << (len - pos)) % mod * ret1 % mod + ret2) % mod ;
}
}
# undef int
int main() {
# define int long long
int T = read() ;
while(T --) {
memset(wn , false , sizeof(wn)) ; memset(wm , false , sizeof(wm)) ;
memset(wk , false , sizeof(wk)) ; len = 0 ;
memset(f , 0 , sizeof(f)) ; memset(g , 0 , sizeof(g)) ;
n = read() - 1 ; m = read() - 1 ; k = read() ; mod = read() ;
for(int i = 0 ; i <= 60 ; i ++)
if((n & (1ull << i)) || (m & (1ull << i)) || (k & (1ull << i)))
len = i + 1 ;
for(int i = 1 ; i <= len ; i ++) {
wn[i] = (n & (1ull << (len - i))) ;
wm[i] = (m & (1ull << (len - i))) ;
wk[i] = (k & (1ull << (len - i))) ;
}
dfs(1 , true , true , true) ;
ans = ((f[1][1][1][1] % mod - k % mod * g[1][1][1][1] % mod) % mod + mod) % mod ;
printf("%lld\n",ans) ;
}
return 0 ;
}