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 ;
}
本文介绍了一种解决特定子矩阵计数问题的有效算法。通过枚举子矩阵边界并利用数状数组进行快速查找,实现对所有和在指定范围内的子矩阵进行计数,总时间复杂度为O(n² * (m + m * log m))。
962

被折叠的 条评论
为什么被折叠?



