搬旧博客到新电脑失败……重新搭了一个?
# 题面 对于一个 $k\times k$ 的矩阵 $A$,定义 $Iv(A)$:
现给定 $n\times n$ 的矩阵 $B$ 和正整数 $m$。求 $B$ 的每个大小为 $m\times m$ 的子矩阵 $B’$ 的 $Iv(B’)$ 之和,对 $10007$ 取模。
> 数据规模:$n\le 500$;$B_{i,j}\le10^4$
# 解析 比较麻烦的是绝对值,于是想到可以先把所有 $B_{i,j}$ 从小到大排序,设排序后为 $B_{x_1,y_1},B_{x_2,y_2},\cdots,B_{x_{n^2},y_{n^2}}$。
那么可以这样计算:
其中 $F_{(x_i,y_i),(x_j,y_j)}$ 表示有多少个子矩阵中同时包含 $(x_1,y_1),(x_2,y_2)$,正确性显然。
可以知道:
当 $i\le j$ 时:$|B_{x_i,y_i}-B_{x_j,y_j}|=B_{x_j,y_j}-B_{x_i,y_i}$
当 $i>j$ 时:$|B_{x_i,y_i}-B_{x_j,y_j}|=B_{x_i,y_i}-B_{x_j,y_j}$
于是上面的式子可以换个写法:
相当于把 $B_{x_i,y_i}$ 的贡献拆成了 $+B_{x_i,y_i}$ 的部分和 $-B_{x_i,y_i}$ 的部分(实际上还有 $i=j$ 的情况,但是贡献为 $0$,就不管了)。
于是就需要对于每一个 $i$,快速地计算上式中的两个 $F$ 的求和式。
可以想到从小到大枚举 $i$,维护 $\sum_{j=1}^{i-1}F_{(x_i,y_i),(x_j,y_j)}$。问题转换为一种“矩形框点 ”的经典问题。考虑把一个 $m\times m$ 的子矩阵用它的右下角坐标表示 ,那么能框住点 $(x,y)$ 的矩形为 $\left(\max\{x,m\},\max\{y,m\}\right)\to\left(\min\{x+m-1,n\},\min\{y+m-1,n\}\right)$。如下图(两个橙色 $4\times4$ 的矩形为能框住蓝色位置的最靠左上的矩形和最靠右下的矩形;红色区域是能框住蓝色位置的矩形右下角区域):
于是我们可以把表示右下角的这块矩形(红色)的所有数 $+1$。然后查询一下能框住当前位置的所有矩形的右下角位置的值之和。就可以求到 $\sum_{j=1}^{i-1}F_{(x_i,y_i),(x_j,y_j)}$ 了。
同理,反过来从大到小枚举 $i$,就可以求 $\sum_{j=i+1}^{n^2}F_{(x_i,y_i),(x_j,y_j)}$ 了。
现在需要解决的问题是:在我们的操作中,出现了给子矩形 $+1$、求一个子矩形所有数的和。那么可以用二维树状数组 (内存开销小一点,用二维线段树的话内存low不住)维护,既然一维树状数组可以区间加区间查询,那二维当然也可以,只是比较麻烦……
> Hint
其实不需要真的把 $i$ 从大到小、从小到大做两遍,可以一开始把二维树状数组的所有值赋为 $-(m^2-1)$。
意思是当前每个可以框住 $(x,y)$ 的矩形中,有 $(m^2-1)$ 个位置比 $(x,y)$ 大,然后因为 $(x,y)$ 和比它大的位置相减取绝对值后是 $-B_{x,y}$,所以乘上 $-1$。
然后每次从小到大枚举 $i$,每次把能框住 $(x_i,y_i)$ 的矩形右下角的位置 $+2$,其实是 $+1-(-1)$;即少了一个比 $(x,y)$ 大的数于是 $-(-1)$,多了一个比 $(x,y)$ 小的数于是 $+1$。
这样的话,每次查询能框住 $(x_i,y_i)$ 的矩形右下角的值之和就直接等于 $\sum_{j=1}^{i-1}F_{(x_i,y_i),(x_j,y_j)}-\sum_{j=i+1}^{n^2}F_{(x_i,y_i),(x_j,y_j)}$。
反正我代码里是这么写的 awa
# 源代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 #include <cstdio> #include <cstring> #include <algorithm> using namespace std ;const int N=500 ,MOD=1e4 +7 ;struct NUMBER { int num; NUMBER(){} NUMBER(int x):num((x%MOD+MOD)%MOD){} NUMBER operator +(const NUMBER &B)const { int res=num+B.num; if (res>=MOD) res-=MOD; return res; } NUMBER operator -(const NUMBER &B)const { int res=num-B.num; if (res<0 ) res+=MOD; return res; } NUMBER operator *(const NUMBER &B)const { int res=num*B.num%MOD; if (res<0 ) res+=MOD; return res; } void operator +=(const NUMBER &B){ (*this )=(*this )+B; } }; struct NODE {int val,x,y;}nod[N*N+3 ];int n,m;NUMBER tre[N+3 ][N+3 ][4 ]; #define lowbit(x) (x&-x) void Update (int x,int y,int v) { NUMBER ad[4 ]={v,v*(x-1 )%MOD,v*(y-1 )%MOD,v*(x-1 )%MOD*(y-1 )%MOD}; for (int i=x;i<=n;i+=lowbit(i)) for (int j=y;j<=n;j+=lowbit(j)) for (int k=0 ;k<4 ;k++){ tre[i][j][k]+=ad[k]; } } void Query (int x,int y,NUMBER *res) { for (int i=0 ;i<4 ;i++) res[i]=0 ; for (int i=x;i;i-=lowbit(i)) for (int j=y;j;j-=lowbit(j)) for (int k=0 ;k<4 ;k++){ res[k]+=tre[i][j][k]; } } NUMBER extmp[4 ][4 ]; NUMBER QMatrix (int L,int R,int U,int D) { Query(L-1 ,U-1 ,extmp[0 ]); Query(L-1 ,D,extmp[1 ]); Query(R,U-1 ,extmp[2 ]); Query(R,D,extmp[3 ]); for (int i=0 ;i<4 ;i++){ extmp[3 ][i]=extmp[3 ][i]-extmp[2 ][i]-extmp[1 ][i]+extmp[0 ][i]; extmp[2 ][i]=extmp[2 ][i]-extmp[0 ][i]; extmp[1 ][i]=extmp[1 ][i]-extmp[0 ][i]; } NUMBER Lx(R-L+1),Ly(D-U+1); NUMBER r(R),d(D); NUMBER ret=Lx*Ly*extmp[0 ][0 ] +Lx*d*extmp[1 ][0 ] -Lx*extmp[1 ][2 ] +Ly*r*extmp[2 ][0 ] -Ly*extmp[2 ][1 ] +r*d*extmp[3 ][0 ] -d*extmp[3 ][1 ] -r*extmp[3 ][2 ] +extmp[3 ][3 ]; return ret; } void UMatrix (int L,int R,int U,int D,int v) { Update(L,U,v); Update(R+1 ,D+1 ,v); Update(L,D+1 ,-v); Update(R+1 ,U,-v); } int Re () { int a=0 ,c=getchar(); while (c<'0' || '9' <c) c=getchar(); while ('0' <=c && c<='9' ) a=(a<<1 )+(a<<3 )+c-'0' ,c=getchar(); return a; } bool cmp (NODE A,NODE B) {return A.val<B.val;}int main () { n=Re();m=Re(); for (int i=1 ,tmp=0 ;i<=n;i++) for (int j=1 ;j<=n;j++){ tmp++; nod[tmp].val=Re(); nod[tmp].x=i; nod[tmp].y=j; } sort(nod+1 ,nod+1 +n*n,cmp); UMatrix(1 ,n,1 ,n,((1 -m*m)%MOD+MOD)%MOD); NUMBER ans (0 ) ; for (int i=1 ;i<=n*n;i++){ int xi=nod[i].x,yi=nod[i].y; int L=max(m,xi),R=min(n,xi+m-1 ), U=max(m,yi),D=min(n,yi+m-1 ); NUMBER res=QMatrix(L,R,U,D); ans+=res*nod[i].val; UMatrix(L,R,U,D,2 ); } printf ("%d\n" ,(ans*2 ).num); return 0 ; }
The End Thanks for reading! “烽烟乱世中怀抱勇气,慨然孤注手中棋” -《易水决》