http://www.spoj.pl/problems/KPMATRIX/
题意:
给你一个N*M的矩阵,N,M<=250,所有和 >=A && <=B的子矩阵的个数。
思路:
首先我们枚举子矩阵的上下边,复杂度为O(n ^ 2), 然后我们处理出前缀和sum[x] , 当我们在找以x为子矩阵的右边界的子矩阵的时候,就是要找有多少个i,使得 A<= sum[x] - sum[i] <=B ,也就是 sum[x] - B <= sum[i] <= sum[x] - A ,也就是说在某个位置x,我们只要找到它前面一个有多少个i,满足sum[x] - B <= sum[i] <= sum[x] - A ,这个查找是可以在O( logm )的时间内找到的(用一个数状数组维护即可),但是因为 -10^9 <= sum[i] <=10^9 ,所以我们还需要对所有的数进行离散化处理。这样本题的总时间复杂度就是:O(n^2*(m + m*logm) ) 。
代码:
#include <stdio.h> #include <string.h> #include <algorithm> const int NN = 260 ; int N,M, A, B; int map[NN][NN] ; int sum[NN] ; int sumB[NN] , sumA[NN] ; int xx[NN*3] ; int C[3 * NN] ; int find( int val , int l ,int r ){ while( l<=r ){ int mid = (l + r) >> 1 ; if( xx[mid] == val ) return mid ; if( xx[mid] < val ) l = mid + 1 ; else r = mid - 1 ; } return -1 ; } inline int lowbit(int a){ return a&(-a) ; } void add(int a , int n){ while( a<=n ){ C[a] ++ ; a += lowbit(a) ; } } int cal_sum(int n){ int res = 0 ; while( n>=1 ){ res += C[n] ; n -= lowbit(n) ; } return res ; } void solve(){ int ans = 0 ; for(int i=1;i<=N;i++){ for(int j=i;j<=N;j++){ int cnt = 1 ; sum[0] = 0 ; sumA[0] = sum[0] - A ; sumB[0] = sum[0] - B - 1 ; xx[cnt++ ] = sum[0] ; xx[cnt++ ] = sumA[0] ; xx[cnt++ ] = sumB[0] ; for(int k=1;k<=M;k++){ sum[k] = sum[k-1] + map[j][k] - map[i-1][k] ; sumA[k] = sum[k] - A ; sumB[k] = sum[k] - B - 1; xx[cnt ++] = sum[k] ; xx[cnt ++] = sumB[k] ; xx[cnt ++] = sumA[k] ; } std::sort( xx + 1 , xx + cnt ) ; int tot = 2 ; for(int i=2;i<cnt;i++){ if( xx[i] == xx[i-1] ) continue ; xx[ tot++ ] = xx[i] ; } tot -- ; memset( C , 0 ,sizeof(C) ); add( find( sum[0] , 1 , tot ) , tot ) ; for(int i=1;i<=M;i++){ int e = find( sumA[i] , 1 , tot ) ; int s = find( sumB[i] , 1 , tot ) ; ans += cal_sum(e) - cal_sum(s) ; add( find( sum[i] ,1 , tot) , tot ) ; } } } printf("%d\n",ans); } int main(){ while( scanf("%d %d",&N,&M) == 2 ){ for(int j=1;j<=M;j++) map[0][j] = 0 ; for(int i=1;i<=N;i++){ for(int j=1;j<=M;j++){ scanf("%d",&map[i][j]) ; map[i][j] = map[i-1][j] + map[i][j] ; } } scanf("%d %d",&A,&B); solve() ; } return 0 ; }