|
代碼:
1 #include<iostream> 2 3 int a,m,n,i,j,k,x1,y1,x2,y2; 4 5 long long sum,s[2002][2002]={0};//數組s用來儲存前綴和 6 7 using namespace std; 8 9 int main() 10 11 { 12 13 scanf("%d%d",&m,&n); 14 15 for(i=1;i<=m;i++)//輸入,賦值二維數組s 16 17 for(j=1;j<=n;j++) 18 19 { 20 21 scanf("%d",&a);//爲了節省空間,以單個變量輸入 22 23 s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a; 24 25 } 26 27 scanf("%d",&k); 28 29 while(k--) 30 31 { 32 33 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 34 35 sum=s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]; 36 37 printf("%lld\n",sum); 38 39 } 40 41 }
代碼分析:
有三種方法:
1. 直接求解,按單個元素記錄。所以,k次查詢裏每次都要有兩個循環,一個橫着在這個區間裏掃描,另外一個豎着掃描。
代碼以下:
1 #include<iostream> 2 3 int a[2010][2010],m,n,i,j,k,b,c,d,e; 4 5 long long sum; 6 7 using namespace std; 8 9 int main() 10 11 { 12 13 scanf("%d%d",&m,&n); 14 15 for(i=1;i<=m;i++) 16 17 { 18 19 for(j=1;j<=n;j++) 20 21 scanf("%d",&a[i][j]); 22 23 } 24 25 cin>>k; 26 27 while(k--) 28 29 { 30 31 sum=0; 32 33 scanf("%d%d%d%d",&b,&c,&d,&e); 34 35 for(i=b;i<=d;i++)//兩次循環 36 37 for(j=c;j<=e;j++) 38 39 sum+=a[i][j]; 40 41 printf("%lld\n",sum); 42 43 44 45 } 46 47 }
這個方法顯然效率過低,兩次循環太耗費時間了,因此要考慮運用前綴和的辦法了。
2. 利用以前數組儲存前綴和的辦法,給這個二維數組每行都求一個前綴和,而後在查詢時,用要求的區間當中每一行的從y1到y2的和,用s[x][y2]-s[x][y1-1](x爲第x行)
因此採用這個方法效率比上一個方法更快。
代碼:
1 #include<iostream> 2 3 int a,m,n,i,j,k,b,c,d,e,s[2002][2002]={0}; 4 5 long long sum; 6 7 int main() 8 9 { 10 11 scanf("%d%d",&m,&n); 12 13 for(i=1;i<=m;i++) 14 15 for(j=1;j<=n;j++) 16 17 { 18 19 scanf("%d",&a); 20 21 s[i][j]=s[i][j-1]+a; 22 23 } 24 25 scanf("%d",&k); 26 27 while(k--) 28 29 { 30 31 sum=0; 32 33 scanf("%d%d%d%d",&b,&c,&d,&e); 34 35 for(i=b;i<=d;i++) 36 37 sum+=(s[i][e]-s[i][c-1]); 38 39 printf("%lld\n",sum); 40 41 } 42 43 }
這個方法不用兩次循環,可仍是有一次循環,但這還不能使人滿意,有沒有更快的方法呢?
分析上兩個方法,咱們發現:
這是第一個方法,它是以單個元素來求解的(以點作前綴和的)。一步步來累加。
第二個方法,前綴和,至關因而以行作單位求解。
既然,以行作前綴和的有了, 以點作前綴和的有了,那能不能以面作前綴和呢?
分析以下:
如此,推算賦值公式就如韋恩圖那樣:
把s[i-1][j]和s[i][j-1]加起來,s[i-1][j-1]部分重疊了,因此要減去,在加上輸入的a,就獲得:
s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a;
而輸出就也像上面同樣,s[x2][y2]是從座標(1,1)開始的,因此要減去s[x2][y1-1]和s[x1-1][y2],s[x1-1][y1-1]被多減了,因此要加上。
代碼:
1 #include<iostream> 2 3 long long sum,a,m,n,i,j,k,x1,y1,x2,y2,s[2002][2002]={0}; 4 5 using namespace std; 6 7 int main() 8 9 { 10 11 scanf("%d%d",&m,&n); 12 13 for(i=1;i<=m;i++) 14 15 for(j=1;j<=n;j++) 16 17 { 18 19 scanf("%d",&a); 20 21 s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a; 22 23 } 24 25 scanf("%d",&k); 26 27 while(k--) 28 29 { 30 31 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 32 33 sum=s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]; 34 35 printf("%lld\n",sum); 36 37 } 38 39 }
這個方法只用一次運算便求出瞭解,因此它是三個方法中最快的方法。