数位dp题。
f[i][0/1][0/1][0/1]表示从高到低第i位,是否到n的上界,是否到m的上界,当前异或结果是否到k的下界。
对于每个状态记录合法方案数和所有合法i,j的异或和,对于每一位枚举n和m选0还是1转移即可。
#include<bits/stdc++.h> #define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout); #define N 2000000 #define inf 123456789123456789 #define db double //#define P 1000000007 #define int long long #define mid (l+r>>1) #define d(x) (x>>cur-1&1) using namespace std; int n,m,k,P,T; struct node{int x,y;}mp[70][2][2][2]; node dp(int cur,int nx,int mx,int kx){ if(!cur) return {1,0}; if(mp[cur][nx][mx][kx].x) return mp[cur][nx][mx][kx]; node res={0,0}; for(int i=0;i<=(d(n)||!nx);i++){ for(int j=0;j<=(d(m)||!mx);j++){ if(kx&&d(k)>(i^j)) continue; node v=dp(cur-1,nx&&i==d(n),mx&&j==d(m),kx&&(i^j)==d(k)); (res.x+=v.x)%=P; (res.y+=(((i^j)<<(cur-1))%P*v.x%P+v.y)%P)%=P; } } return mp[cur][nx][mx][kx]=res; } signed main(){ scanf("%lld",&T); while(T--){ memset(mp,0,sizeof(mp)); scanf("%lld%lld%lld%lld",&n,&m,&k,&P);n--;m--; node v=dp(63,1,1,1); printf("%lld ",(v.y-k%P*v.x%P+P)%P); } return 0; }