Codeforces Round #219 (Div. 2) D. Counting Rectangles is Fun

http://codeforces.com/contest/373/problem/D

D. Counting Rectangles is Fun
time limit per test
4 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

There is an n × m rectangular grid, each cell of the grid contains a single integer: zero or one. Let's call the cell on the i-th row and the j-th column as (i, j).

Let's define a "rectangle" as four integers a, b, c, d (1 ≤ a ≤ c ≤ n; 1 ≤ b ≤ d ≤ m). Rectangle denotes a set of cells of the grid {(x, y) :  a ≤ x ≤ c, b ≤ y ≤ d}. Let's define a "good rectangle" as a rectangle that includes only the cells with zeros.

You should answer the following q queries: calculate the number of good rectangles all of which cells are in the given rectangle.

Input

There are three integers in the first line: nm and q (1 ≤ n, m ≤ 40, 1 ≤ q ≤ 3·105). Each of the next n lines contains m characters — the grid. Consider grid rows are numbered from top to bottom, and grid columns are numbered from left to right. Both columns and rows are numbered starting from 1.

Each of the next q lines contains a query — four integers that describe the current rectangle, abcd (1 ≤ a ≤ c ≤ n; 1 ≤ b ≤ d ≤ m).

Output

For each query output an answer — a single integer in a separate line.

Sample test(s)
input
5 5 5
00101
00000
00001
01000
00001
1 2 2 4
4 5 4 5
1 2 5 2
2 2 4 5
4 2 5 3
output
10
1
7
34
5
input
4 7 5
0000100
0000010
0011000
0000000
1 7 2 7
3 1 3 1
2 3 4 5
1 2 2 7
2 2 4 7
output
3
1
16
27
52

題意分析:查詢每個區域內的只包含0的矩形個數。

思路:二重遞歸

對待查詢區域,先切分成兩半,統計跨越兩個子區域的矩形個數,然後遞歸就行。問題是如何統計跨越兩個子區域的矩形個數(僅僅包含0)。對於分界線,統計兩側連續爲0的長度,得到一些長度不等的柱子Ai, Bi。問題變成統計這兩堆柱子內部的矩形個數(跨越)。枚舉以第i個柱子爲結尾的矩形數目,如果Ai前面存在Aj>Ai(j<i) 那麼超出的那些部分將會是無效的(黑色部分,統計以i爲結尾的矩形數目),因此需要有“削平”操作,B是一樣的。然後以第i個結尾的矩形數目=∑(Ai*Bi)。 這樣O(n*n)就可以計算完。



二重二分複雜度=log(n+n)

整體複雜度,log(n+n)*n*n

代碼:

#include<algorithm>
#include<iostream>
#include<fstream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<ctime>

using namespace std;
#define FOR(i,a,b)    for(int i=a;i<b;i++)
#define FORD(i,a,b)    for(int i=a;i>b;i--)
#define MST(a,num)    memset(a,num,sizeof(a))
#define MCP(d,s)    memcpy(d,s,sizeof(s))
#define WH(n)         while(scanf("%d", &n) != EOF)
#define WHZ(n)         while(scanf("%d", &n) != EOF && n != 0)
#define SCF(a)        scanf("%d",&a)
#define SCFS(a)        scanf("%s",a)
#define PRF(a)        printf("%d",a)
#define PRS(a)        printf("%s",a)
#define PRFF(a)        printf("%d\n",a)
#define PRSF(a)        printf("%s\n",a)
#define PRFFU(a)        printf("%I64d\n",a)

#define PI acos(-1)
#define max3(a,b,c)     max(max(a,b),c)
#define max4(a,b,c,d)     max(max(a,b),max(c,d))

#define FORE(e,x) for(__typeof(x.begin()) e=x.begin(); e!=x.end(); e++) //foreach(it, ans ) cout<<*it<<" ";
#define all(a) (a).begin(),(a).end() //sort(all(v));
#define len(a) ((int)(a).size())
#define pb push_back
#define mk make_pair
#define V(etype) vector<etype>

typedef __int64 Uint;
typedef vector<int> Vint;
typedef pair<int,int>mypair;

#define INF 0x3f3f3f3f
#define eps 1e-9
const int N=40+2;
int n,m,q;
int d[4][N][N];
char str[N][N];
int A[N];
int B[N];
int flag[N][N][N][N];
Uint count(int i,int ii,int j,int jj){
if(flag[i][ii][j][jj]+1)return flag[i][ii][j][jj];
if(i==ii&&j==jj)return flag[i][ii][j][jj]=(str[i][j]=='0');
Uint ret=0;
int mid;
if(jj-j<ii-i){
	mid=(i+ii)>>1;
	for(int t=0;t+j<=jj;t++){
		A[t]=mid-max(i-1,d[0][mid][t+j]);
		B[t]=min(ii+1,d[2][mid+1][t+j])-(mid+1);
		for(int r=t-1;r>=0 && A[r]>A[t];r--)A[r]=A[t];
		for(int r=t-1;r>=0 && B[r]>B[t];r--)B[r]=B[t];
		for(int r=t;r>=0 && A[r]>0 && B[r]>0;r--)ret+=A[r]*B[r];
	}
	ret+=count(i,mid,j,jj)+count(mid+1,ii,j,jj);
}
else{
	mid=(j+jj)>>1;
	for(int t=0;t+i<=ii;t++){
		A[t]=mid-max(j-1,d[1][t+i][mid]);
		B[t]=min(jj+1,d[3][t+i][mid+1])-(mid+1);
		for(int r=t-1;r>=0 && A[r]>A[t];r--)A[r]=A[t];
		for(int r=t-1;r>=0 && B[r]>B[t];r--)B[r]=B[t];
		for(int r=t;r>=0 && A[r]>0 && B[r]>0;r--)ret+=A[r]*B[r];
	}
	ret+=count(i,ii,j,mid)+count(i,ii,mid+1,jj);
}
//printf("%d %d %d %d=%d\n",i+1,ii+1,j+1,jj+1,ret);
return flag[i][ii][j][jj]=ret;
}
void getD(){
FOR(i,0,n)FOR(j,0,m){
d[0][i][j]=(str[i][j]=='0')?(i?d[0][i-1][j]:-1):i;
d[1][i][j]=(str[i][j]=='0')?(j?d[1][i][j-1]:-1):j;
}
FORD(i,n-1,-1)FORD(j,m-1,-1){
d[2][i][j]=(str[i][j]=='0')?((i==n-1)?n:d[2][i+1][j]):i;
d[3][i][j]=(str[i][j]=='0')?((j==m-1)?m:d[3][i][j+1]):j;
}
}
int main(){
int a,b,c,d;
while(cin>>n>>m>>q){
FOR(i,0,n)SCFS(str[i]);
getD();
MST(flag,-1);
while(q--){
scanf("%d%d%d%d",&a,&b,&c,&d);
Uint ret=count(--a,--c,--b,--d);
PRFFU(ret);
}

}

return 0;
}
/*
5 5 5
00101
00000
00001
01000
00001
1 2 2 4
4 5 4 5
1 2 5 2
2 2 4 5
4 2 5 3
*/


發佈了51 篇原創文章 · 獲贊 8 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章