一、題目
二、解法
不要把這道題從圖形的角度考慮,我們考慮它的本質就是求:
可以考慮數位,只不過特殊的是我們要同時維護兩個數,而且數位指的是二進制位,設爲到了二進制的第位,是否頂到的上界,是否頂到的上界,是否頂到的上界。
轉移就枚舉兩個數當前位選什麼,然後驗證,這裏還要維護一個個數,轉移時個數直接累加,答案就加上當前位的貢獻在乘上個數,剩下的就是數位日常操作了,貼個代碼。
#include <cstdio>
#include <cstring>
#define int long long
int read()
{
int x=0,flag=1;
char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int T,n,m,k,p;
int f[62][2][2][2],g[62][2][2][2];
void init()
{
n=read();
m=read();
k=read();
p=read();
memset(f,0,sizeof f);
memset(g,0,sizeof g);
g[61][1][1][1]=1;
for(int i=60; i>=0; i--)
{
int x=(n>>i)&1,y=(m>>i)&1,z=(k>>i)&1;
for(int a=0; a<2; a++)
for(int b=0; b<2; b++)
for(int c=0; c<2; c++)
if(f[i+1][a][b][c] || g[i+1][a][b][c])
for(int xx=0; xx<2; xx++)
for(int yy=0; yy<2; yy++)
{
int zz=xx^yy;
if((a && xx>x) || (b && yy>y) || (c && zz<z)) continue;
int aa=(a && xx==x),bb=(b && yy==y),cc=(c && zz==z);
g[i][aa][bb][cc]=(g[i][aa][bb][cc]+g[i+1][a][b][c])%p;
f[i][aa][bb][cc]=(f[i][aa][bb][cc]+f[i+1][a][b][c]+(zz-z+p)%p*((1ll<<i)%p)%p*g[i+1][a][b][c]%p)%p;
}
}
printf("%lld\n",f[0][0][0][0]);
}
signed main()
{
T=read();
while(T--)
{
init();
}
}