NC54664. 捡金币
描述
输入描述
第一行是一个整数 T(1<=T<=100),表示数据组数。
对于每一组数据:
第一行是 2 个整数 n,m(1<=n,m<=1000) ,表示棋盘的尺寸。
接下来一共 n 行,每行 m 个整数,用以表示棋盘内每个格子放入的金币数量,每个格子内放入的金币数量 v 满足 (1<=v<=1000000)。
接下来 1 个整数 q(1<=q<=100000) 表示询问个数。
接下来一共 q 行,每行 3 个整数 x,y,k(1<=x<=n, 1<=y<=m, 1<=k<=max(n,m)) 表示一组询问。
输出描述
对于每一个询问 x,y,k ,输出一行包括一个数字表示离 (x,y) 距离不超过 k 的所有格子里的金币总和是多少。
示例1
输入:
1 3 4 1 2 3 4 5 6 7 8 9 10 11 12 4 2 2 0 2 2 1 2 2 2 2 2 3
输出:
6 30 62 78
C++14(g++5.4) 解法, 执行用时: 355ms, 内存消耗: 48872K, 提交时间: 2019-11-17 17:59:45
#include<cstdio> #include<cstring> using namespace std; int t,i,j,x,y,x1,y1,k,n,m,q,n1,m1; int a[2000][2000]; long long b[2000][2000]; inline int max(int a,int b) { return a>b?a:b; } inline int min(int a,int b) { return a<b?a:b; } int main() { scanf("%d",&t); for (;t;--t) { scanf("%d%d",&n,&m); memset(a,0,sizeof(a)); for (i=1;i<=n;++i) for (j=1;j<=m;++j) scanf("%d",&a[i-j+m][i+j-1]); n1=n+m-1; m1=n+m-1; for (i=1;i<=n1;++i) for (j=1;j<=m1;++j) b[i][j]=a[i][j]+b[i-1][j]+b[i][j-1]-b[i-1][j-1]; scanf("%d",&q); for (;q;--q) { scanf("%d%d%d",&x,&y,&k); x1=x-y+m; y1=x+y-1; printf("%lld\n",b[min(x1+k,n1)][min(y1+k,m1)]-b[max(x1-k-1,0)][min(y1+k,m1)]-b[min(x1+k,n1)][max(y1-k-1,0)]+b[max(x1-k-1,0)][max(y1-k-1,0)]); } } }
C++11(clang++ 3.9) 解法, 执行用时: 1390ms, 内存消耗: 9820K, 提交时间: 2019-11-17 16:16:15
# include <iostream> # include <cstdio> using namespace std; long long A[1010][1010]; int main(void) { //freopen("aaa.in","r",stdin); int T; scanf("%d",&T); while(T--) { int n,m; scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) for (int j=1,a;j<=m;j++) { scanf("%d",&a); A[i][j] = A[i][j-1]+a; } int q,x,y,k; scanf("%d",&q); while(q--) { scanf("%d%d%d",&x,&y,&k); long long ans=0; int r=min(y+k,m),l=max(1,y-k),up,low; ans+=A[x][r]-A[x][l-1]; for (int i=k-1;i>=0;i--) { r = min(y+i,m);l = max(1,y-i); up = x-(k-i); if (up>=1) ans+=A[up][r]-A[up][l-1]; low = x+(k-i); if (low<=n) ans+=A[low][r]-A[low][l-1]; } printf("%lld\n",ans); } } return 0; }