Codeforces 809C - Find a car(找性质)
首先拿到这类题第一步肯定要分析题目给出的矩阵有什么性质。稍微打个表即可发现题目要求的矩形是一个分形。形式化地说,该矩形可以通过以下方式生成:\(A_n\) 为一个 \(2^n\times 2^n\) 的矩阵,\(A_0=[1]\),\(A_i=\begin{bmatrix}A_{i-1}&A'_{i-1}\\A'_{i-1}&A_{i-1}\end{bmatrix}\),其中 \(A'_{i}\) 也是一个 \(2^i\times 2^i\) 的矩阵,其第 \(x\) 行 \(y\) 列的元素为 \(A_i\) 第 \(x\) 行 \(y\) 列的元素加上 \(2^i\)。
接下来就是我想不到的地方了,碰到这类生成方式与二进制联系异常紧密的矩阵,我们要尝试将其与位运算建立联系。这里就有一个性质,那就是该矩阵第 \(x\) 行第 \(y\) 列的数为 \((x-1)\oplus(y-1)+1\),证明可以大力归纳,应该不难,这里就不再赘述了。要说怎么发现的我也不知道,反正对于我这类没脑子选手肯定是想不到的咯。
于是此题可以转化为求 \(\sum\limits_{i=l_1}^{r_1}\sum\limits_{j=l_2}^{r_2}(i-1)\oplus(j-1)+1[(i-1)\oplus(j-1)+1\le k]\)。看到这类矩形求和的问题首先将其差分拆成四个形如 \(\sum\limits_{i=0}^{x-1}\sum\limits_{j=0}^{y-1}i\oplus j+1[i\oplus j+1\le k]\) 的部分。于是现在问题转化为怎么求左边这坨东西。这里又有一个我想不到的套路,发现这东西长得挺像二维树状数组,因此我们可以将这个矩阵拆成 \(\log^2n\) 个形如 \([x-\text{lowbit}(x),x),[y-\text{lowbit}(y),y)\) 的子矩阵,不妨假设 \(\text{lowbit}(x)\ge \text{lowbit}(y)\),记 \(t=(x-\text{lowbit}(x))\oplus (y-\text{lowbit}(y))\),那么显然 \([x-\text{lowbit}(x),x),[y-\text{lowbit}(y),y)\) 中任意两数异或起来的值刚好是 \([t,t+\text{lowbit}(x))\) 中每个数恰好出现 \(\text{lowbit}(y)\) 次,因为 \(\forall v\in[t,t+\text{lowbit}(x)),j\in [y-\text{lowbit}(y),y)\) 都有 \(v\oplus j\in[x-\text{lowbit}(x),x)\),这个稍微想想就能想明白,因此对于所有形如 \([x-\text{lowbit}(x),x),[y-\text{lowbit}(y),y)\) 可以 \(\mathcal O(1)\) 计算贡献。因此单次时间复杂度 \(\log^2n\),总复杂度 \(T\log^2n\)。
可能有几个地方讲得不是太明白,具体看代码罢。
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
#define y0 y101010101010
#define y1 y010101010101
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MOD=1e9+7;
const int INV2=5e8+4;
int sum(int l,int r){return 1ll*(l+r)*(r-l+1)%MOD*INV2%MOD;}
int calc(int l1,int r1,int l2,int r2,int k){
if((r1-l1+1)<(r2-l2+1)) l1^=l2^=l1^=l2,r1^=r2^=r1^=r2;
int tl=(l1^l2)&~(r1-l1),tr=min(tl+r1-l1,k-1);
if(tl>k-1) return 0;return 1ll*(r2-l2+1)*sum(tl+1,tr+1)%MOD;
}
int solve(int x,int y,int k){
int ans=0;
for(int i=x;i;i&=(i-1)) for(int j=y;j;j&=(j-1))
ans=(ans+calc(i&(i-1),i-1,j&(j-1),j-1,k))%MOD;
// printf("%d %d %d %d\n",x,y,k,ans);
return ans;
}
int main(){
int qu;scanf("%d",&qu);
while(qu--){
int x1,y1,x2,y2,k;scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&k);
printf("%d\n",((solve(x2,y2,k)-solve(x2,y1-1,k)-solve(x1-1,y2,k)+solve(x1-1,y1-1,k))%MOD+MOD)%MOD);
}
return 0;
}
/*
1
6 3 9 5 1
*/

浙公网安备 33010602011771号