Codeforce 364E 二维分治 包含K个1的 子矩阵个数

题目链接:http://codeforces.com/problemset/problem/364/E

 时间复杂度O(n*m*K * (lgn + lgm) )  (lgn +lgm)是分治的复杂度

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<algorithm>

#define N 2550
#define Mid(x,y) ((x+y)>>1)
using namespace std;
int n, m, K;
__int64 ans;
int s[N][N], up[8], down[8];
inline int sum(int x1, int x2, int y1, int y2){ //求出该矩阵的1个数
	return s[x2][y2] - s[x2][y1] - s[x1][y2] + s[x1][y1];
}
void work(int x1, int x2, int y1, int y2, bool dir){ //横竖交替割  计算 满足条件 且在水平中线上的子矩阵个数
	if(x1 == x2 || y1 == y2)return ;
	if((x1+1 == x2) && (y1+1 == y2))
	{ ans += sum(x1, x2, y1, y2) == K; return ;}

	if(dir)//dir == true 表示划水平线
	{
		int mid = Mid(x1, x2);
		work(x1,  mid,  y1, y2, !dir);//分治,分别计算 水平中线 割开后的2个子矩阵
		work(mid, x2, y1, y2, !dir);
		//先在中间作一条水平线
		//然后统计跨越水平线并且恰好含有k个1的矩形有多少个
		//然后这个统计过程呢就需要两个数组
		for(int i = y1; i < y2; i++)
		{
			up[0] = down[0] = mid;  //显然当 1个数为0个时, x坐标 == mid
			for(int k = 1; k <= K+1; k++)
				up[k] = x1, down[k] = x2;
			for(int j = i+1; j<=y2; j++) 
			{
				//对于矩阵 (x,i)-(mid,j) 这里面1的个数 < k个时 x的坐标就是 up[k] * 并且upbarrier贴得最紧

				for(int k = 1; k <= K+1; k++)
					while(sum(up[k],  mid, i, j) >=k)up[k]++;

				for(int k = 1; k <= K+1; k++)
					while(sum(mid, down[k], i, j)>=k)down[k]--;

				for(int k = 0; k <= K; k++)// 此句何意
					ans += (up[k] - up[k+1]) * (down[K-k+1] - down[K-k]);
				//那么up[k]所在矩阵 和 up[k+1] 所在矩阵 之间要么1个数相等 要么相差为1 (相等乘法就是0,相差为1就是所要结果)
			}
		}
	}
	else //划垂直线
	{
		int mid = Mid(y1, y2);
		work(x1, x2, y1,   mid, !dir);
		work(x1, x2, mid, y2, !dir);

		for(int i = x1; i < x2; i++)
		{
			up[0] = down[0] = mid;
			for(int k = 1; k <= K+1; k++)
				up[k] = y1, down[k] = y2;
			for(int j = i+1; j <= x2; j++)
			{
				for(int k = 1; k <= K+1; k++)
					while(sum(i, j, up[k], mid) >= k) up[k]++;

				for(int k = 1; k <= K+1; k++)
					while(sum(i, j, mid, down[k])>=k) down[k]--;

				for(int k = 0; k <= K; k++)
					ans += (up[k] - up[k+1]) * (down[K-k+1] - down[K-k]);
			}
		}
	}
}
int main(){
	while(~scanf("%d %d %d",&n,&m,&K)){
		memset(s[0], 0, sizeof(s[0]));
		for(int i = 1; i <= n; i++)
		{   char c[N];scanf("%s",c);
		for(int j = 1; j <= m; j++)
			s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + c[j-1]-'0';
		}
		ans = 0;
		work(0, n, 0, m, false);
		printf("%I64d\n",ans);
	}
	return 0;
}
/*
3 3 2
101
000
101

5 5 1
00000
00000
00100
00000
00000

5 5 6
01010
10101
01010
10101
01010

3 3 0
001
010
000

*/

你可能感兴趣的:(Codeforce 364E 二维分治 包含K个1的 子矩阵个数)