听说标解是个神数位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; }