一开始以为是一个高明的数据结构,后来发现直接拆式子就行了
举个2∗2矩阵的例子
第一个矩阵
$$
\begin{bmatrix}
a_1 & a_2 \\
a_3 & a_4 \\
\end{bmatrix}
$$
第二个矩阵
$$
\begin{bmatrix}
b_1 & b_2 \\
b_3 & b_4 \\
\end{bmatrix}
$$
那么我们来乘一下,结果是
$$
\begin{bmatrix}
a_1*b_1+a_2*b_3 & a_2*b_4+a_1*b_2 \\
a_3*b_1+a_4*b_3 & a_4*b_4+a_3*b_2 \\
\end{bmatrix}
$$
加一下得到a1∗(b1+b2)+a2∗(b3+b4)+a3∗(b1+b2)+a4∗(b3+b4)
组合一下得到(a1+a3)∗(b1+b2)+(a2+a4)∗(b3∗b4)
也就是第一个矩阵记录向上的前缀和,第二个矩阵记录向左的前缀和
然后乘一下就好了
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 | #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; const register int N=2005; static int n,m,a[N][N],b[N][N]; inline void Read( register int &x){ register char ch; while ((ch= getchar ())< '0' || ch> '9' ); x=ch- '0' ; while ((ch= getchar ())>= '0' && ch<= '9' )x=x*10+ch- '0' ; } int main(){ freopen ( "2901.in" , "r" ,stdin); freopen ( "2901.out" , "w" ,stdout); Read(n);Read(m); for ( register int i=1;i<=n;i++) for ( register int j=1;j<=n;j++)Read(a[i][j]),a[i][j]+=a[i-1][j]; for ( register int i=1;i<=n;i++) for ( register int j=1;j<=n;j++)Read(b[i][j]),b[i][j]+=b[i][j-1]; while (m--){ register int A,B,C,D; Read(A);Read(B);Read(C);Read(D); if (A>C)A^=C^=A^=C; if (B>D)B^=D^=B^=D; register long long ans=0; for ( register int i=1;i<=n;i++)ans+=(1ll*a[C][i]-a[A-1][i])*(1ll*b[i][D]-b[i][B-1]); printf ( "%lld\n" ,ans); } return 0; } |