(好久没写博客了。。。果然这种 cf 后两题自己还是想不出来。。。)
题意:有一个1e9×1e9的矩阵,矩阵中的每一个数字是自己左侧所在行和上侧所在列所有数字中没有出现的最小的数字。问给定x1,x2,y1,y2,k,再给定的矩形范围内不不大于k的数字求和。
做法:这个矩阵里面的数是 ((i-1)^(j-1)+1)(i,j为横纵坐标)。当x,y某一区间为(1,(1<<m))时,对于y区间内的每一个数可以取满x区间的数。所以递归处理二进制的每一位,当不满足上述条件时,就分别处理 y区间和x区间 是否向前移动(1<<(p-1))(当前为第p位),递归的时候记录前面移动的数字和用来判断防止最终大于k。
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int mod=1e9+7; 5 LL sum(LL l,LL r){ 6 return (l+r)*(r-l+1)/2%mod; 7 } 8 int solve(int x1,int x2,int y1,int y2,int k,int p,int add){ 9 x1=max(1,x1); x2=min(x2,(1<<p)); 10 y1=max(1,y1); y2=min(y2,(1<<p)); 11 if(x1>x2||y1>y2) return 0; 12 if(x2-x1<y2-y1) 13 return solve(y1,y2,x1,x2,k,p,add); 14 if(x1==1&&x2==(1<<p)){ 15 LL cnt=(y2-y1+1); 16 LL l=add+1; 17 LL r=min((LL)k,(LL)add+(LL)(1<<p)); 18 if(l>r) return 0; 19 return cnt*sum(l,r)%mod; 20 } 21 int ans=0,h=(1<<(p-1)); 22 ans=(ans+solve(x1,x2,y1,y2,k,p-1,add))%mod; 23 ans=(ans+solve(x1-h,x2-h,y1,y2,k,p-1,add+h))%mod; 24 ans=(ans+solve(x1,x2,y1-h,y2-h,k,p-1,add+h))%mod; 25 ans=(ans+solve(x1-h,x2-h,y1-h,y2-h,k,p-1,add))%mod; 26 return ans; 27 } 28 int main(){ 29 int q; 30 scanf("%d",&q); 31 while(q--){ 32 int x1,x2,y1,y2,k; 33 scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&k); 34 printf("%d ",solve(x1,x2,y1,y2,k,30,0)); 35 } 36 37 return 0; 38 }