听说标解是个神数位DP什么的。。。讲道理我是辣鸡我不会。
所以说异或运算真的是个神奇的东西,打一张表出来仿佛各处都藏着奇葩的规律,因为有k的限制,所以我们的目的是将整个序列化成若干个等差序列的和,并且每个等差序列从k处断开(因为负数不计入计算),不难发现存在很多个长边为(2^i),短边小于等于长边的矩形,其中每一条长边都是一个打散的等差数列,我们每次从子矩形中拿出最大的一个,计算一个再乘以一共有几条,剩下的部分递归分治解决即可。
#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
#define maxn 1005
void _readLL(long long &x)
{
x=0; char ch=getchar(); bool flag=false;
while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} if(flag)x=-x;
return ;
}
long long n,m,k,p;
long long ans,sum;
void calc(long long ct,long long A0,long long An)
{
sum=0;
if(An<=k)return ;
else if(A0<=k)
{
if((An-k)%2==0) sum=((An-k)/2)%p*((An-k+1)%p)%p;
else sum=((An-k+1)/2)%p*((An-k)%p)%p;
}
else
{
sum=(A0-k+An-k)*(An-A0+1)/2;
if((An+A0-2*k)%2==0) sum=((A0-k+An-k)/2)%p*((An-A0+1)%p)%p;
else sum=((An-A0+1)/2)%p*((A0-k+An-k)%p)%p;
}
sum=((sum%p)*(ct%p))%p; ans=(ans+sum)%p;
return ;
}
long long Findmin(long long L,long long R,long long x)
{
long long e=1; int ni; for(ni=62;ni>=0;ni--)if((R-L+1)>=(e<<ni))break;
return ni>0 ? ((x>>(ni-1))<<(ni-1))^L : x^L;
}
void run(long long X1,long long Y1,long long X2,long long Y2)
{
if(X1>X2 || Y1>Y2 ) return ;
int ni,nj;long long e=1,t;
for(ni=62;ni>=0;ni--)if((X2-X1+1)>=(e<<ni))break;
for(nj=62;nj>=0;nj--)if((Y2-Y1+1)>=(e<<nj))break;
//t=Findmin(X1,X1+(e<<ni)-1,Y1,Y1+(e<<nj)-1);
if(ni<nj){ swap(ni,nj); swap(X1,Y1); swap(X2,Y2); }
if(Y2-Y1+1<=(e<<ni))
{
t=Findmin(X1,X1+(e<<ni)-1,Y1);
calc(Y2-Y1+1,t,t+(e<<ni)-1);
run(X1+(e<<ni),Y1,X2,Y2);
}
else
{
t=Findmin(X1,X1+(e<<ni)-1,Y1);
calc((e<<ni),t,t+(e<<ni)-1);
t=Findmin(X1,X1+(e<<ni)-1,Y1+(e<<ni));
calc(Y2-Y1+1-(e<<ni),t,t+(e<<ni)-1);
run(X1+(e<<ni),Y1,X2,Y2);
// run(X1,Y1+(e<<ni),X1+(e<<ni)-1,Y2);
}
return ;
}
void Debug()
{
long long ans=0;
for(int i=0;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
printf("%d ",i^j);
if((i^j)>=k)ans=(ans+(i^j)-k)%p;
}
putchar('\n');
}
cout<<ans<<endl;
return ;
}
char s[35];int cc;
void out(long long x)
{
if(!x)putchar('0');
if(x<0){x=-x; putchar('-');}
cc=0; while(x){s[++cc]=x%10+'0';x=x/10;}
while(cc){putchar(s[cc]);cc--;}
putchar('\n');
return ;
}
int main()
{
freopen("in.txt","r",stdin);
int T;scanf("%d",&T);
while(T--)
{
ans=0;
_readLL(n);_readLL(m); _readLL(k); _readLL(p);n--; m--;
// Debug();
run(0,0,n,m);
out(ans);
}
return 0;
}