题意:
给定一种矩阵生成方式,现在给一个数组 $A$ ,然后询问某个子矩阵的和,$x,y<1e8$;
思路:
矩阵是无限大的,所求的子矩阵范围也较大,于是就表找规律,发现当$L$为奇数时,周期为$L$,反之为$2*L$;
那么我们就可以把周期一致看作$2*L$,然后做一下前缀和,就可以直接求了。此类题目要善于总结!
1 /* 2 * @Author: windystreet 3 * @Date: 2018-08-06 10:27:38 4 * @Last Modified by: windystreet 5 * @Last Modified time: 2018-08-06 20:48:57 6 */ 7 #include<bits/stdc++.h> 8 9 using namespace std; 10 11 #define X first 12 #define Y second 13 #define eps 1e-5 14 #define gcd __gcd 15 #define pb push_back 16 #define PI acos(-1.0) 17 #define lowbit(x) (x)&(-x) 18 #define bug printf("!!!!! "); 19 #define mem(x,y) memset(x,y,sizeof(x)) 20 21 typedef long long LL; 22 typedef long double LD; 23 typedef pair<int,int> pii; 24 typedef unsigned long long uLL; 25 26 const int maxn = 1e5+2; 27 const int INF = 1<<30; 28 const int mod = 1e9+7; 29 30 int s[110][110]; 31 int a[100]; 32 int sum[110][110]; 33 int L; 34 35 LL cal(int s,int t){ // 计算(0,0,)到(s,t)的前缀和 36 int x = s%L,cntx = s/L; 37 int y = t%L,cnty = t/L; 38 return 1ll*sum[x][L-1]*cnty+1ll*sum[L-1][y]*cntx+1ll*sum[L-1][L-1]*cntx*cnty+1ll*sum[x][y]; 39 } 40 41 void solve(){ 42 int Q,x1,y1,x2,y2; 43 scanf("%d",&L); 44 for(int i=0;i<L;i++){ 45 scanf("%d",&a[i]); 46 } 47 int cur = 0; 48 for(int i=0;i<10*L;++i){ // 矩阵生成器 49 for(int j=0;j<=i;++j){ 50 s[j][i-j] = a[cur]; 51 cur = (cur + 1) % L; 52 } 53 } 54 L = 2*L; 55 sum[0][0] = s[0][0]; // 计算(2*L)*(2*L)矩阵的前缀和 56 for(int i=1;i<L;i++)sum[0][i] = sum[0][i-1] + s[0][i]; 57 for(int i=1;i<L;i++)sum[i][0] = sum[i-1][0] + s[i][0]; 58 for(int i=1;i<L;i++){ 59 for(int j=1;j<L;j++){ 60 sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + s[i][j]; 61 } 62 } 63 scanf("%d",&Q); 64 while(Q--){ 65 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); // 容斥一下 66 printf("%lld ",cal(x2,y2)-cal(x2,y1-1)-cal(x1-1,y2)+cal(x1-1,y1-1)); 67 } 68 return; 69 } 70 71 int main() 72 { 73 // freopen("in.txt","r",stdin); 74 // freopen("out.txt","w",stdout); 75 // ios::sync_with_stdio(false); 76 int t = 1; 77 scanf("%d",&t); 78 while(t--){ 79 // printf("Case %d: ",cas++); 80 solve(); 81 } 82 return 0; 83 }