CF2044H Hard Demon Problem

CF2044H Hard Demon Problem

题意

给出 \(n\times n\) 的二维数组 \(a\),有 \(q\) 个询问,每次询问给出 \(x_1,y_1,x_2,y_2\),求以下函数的值:

cnt=1,ans=0;
for i=x1 to x2:
  for j=y1 to y2:
    ans=ans+a[i][j]*cnt;
    cnt=cnt+1;
return ans;

思路

很考验对前缀和理解的题。

假如我们要算以下二维数组 \(a_{i,j} \pod{1\le i\le n,1\le j\le m}\) 的函数值:

1 2 3
4 5 6
7 8 9

答案即为:

1*1 + 2*2 + 3*3 +
4*4 + 5*5 + 6*6 +
7*7 + 8*8 + 9*9

可以发现每行中都包含了类似 \(\sum_{j=1}^m a_{i,j}\times j\) 的算式,把它提出来,原式变为:

1*1 + 2*2 + 3*3 +
4*1 + 5*2 + 6*3 +
7*1 + 8*2 + 9*3 +

1*0 + 2*0 + 3*0 +
4*3 + 5*3 + 6*3 +
7*6 + 8*6 + 9*6

可以发现剩下的算式每列里也包含了类似 \(\sum_{i=1}^n a_{i,j}\times m\times (i-1)\) 的算式。

于是可以通过预处理出这两个东西的二维前缀和快速计算答案,但是实际计算时的前缀和数组的 \(i\)\(j\) 可能并不是从 \(1\) 开始,这时便可以再维护一个正常的二维前缀和,计算时再将这两个前缀和数组整体减去一个值即可。

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define g(x,y,xx,yy,z) (z[xx][yy]-z[xx][y-1]-z[x-1][yy]+z[x-1][y-1])
int T,n,q,t[2005][2005],a[2005][2005],b[2005][2005],c[2005][2005];
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	cin>>T;
	while(T--){
		cin>>n>>q;
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				cin>>t[i][j];
				a[i][j]=a[i][j-1]+a[i-1][j]-a[i-1][j-1]+t[i][j]*j;
				b[i][j]=b[i][j-1]+b[i-1][j]-b[i-1][j-1]+t[i][j]*i;
				c[i][j]=c[i][j-1]+c[i-1][j]-c[i-1][j-1]+t[i][j];
			}
		}
		while(q--){
			int x,y,xx,yy;
			cin>>x>>y>>xx>>yy;
			cout<<(g(x,y,xx,yy,a)-g(x,y,xx,yy,c)*(y-1))+
			(g(x,y,xx,yy,b)-g(x,y,xx,yy,c)*x)*(yy-y+1)<<" ";
		}
		cout<<endl;
	}
	return 0; 
}
posted @ 2025-03-26 11:04  WuMin4  阅读(12)  评论(0)    收藏  举报