问题 : Snuke‘s Coloring

题目描述

We have a grid with H rows and W columns. At first, all cells were painted white.
Snuke painted N of these cells. The i-th ( 1≤i≤N ) cell he painted is the cell at the ai-th row and bi-th column.
Compute the following:
For each integer j ( 0≤j≤9 ), how many subrectangles of size 3×3 of the grid contains exactly j black cells, after Snuke painted N cells?

Constraints
3≤H≤10^9
3≤W≤10^9
0≤N≤min(10^5,H×W)
1≤ai≤H (1≤i≤N)
1≤bi≤W (1≤i≤N)
(ai,bi)≠(aj,bj) (i≠j)

输入

The input is given from Standard Input in the following format:
H W N
a1 b1
:
aN bN

输出

Print 10 lines. The (j+1)-th ( 0≤j≤9 ) line should contain the number of the subrectangles of size 3×3 of the grid that contains exactly j black cells.

样例输入 Copy
4 5 8
1 1
1 4
1 5
2 3
3 1
3 2
3 4
4 4
样例输出 Copy
0
0
0
2
4
0
0
0
0
0
提示


There are six subrectangles of size 3×3. Two of them contain three black cells each, and the remaining four contain four black cells each.

这个题特点就是数据特别大,输入的点达到了1e6,范围达到了1e9;

所以这个题我们可以转换思路,不再把所有的点表示出来,而是只表示涂过的空间

同时点也不用二维数组存储(防止占用空间过大),转为一维数组,同时为了防止x与y混淆,我们将x*1e9+y表示此点的坐标

同时因为是一个点影响其余8个所以我们着重去研究中心点,用一个中心点表示3*3的矩阵

代码实现:

#include <bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
typedef long long ll;

const int N = (1e5) + 5;
ll res[10];
//存储输出结果
ll e = 1e9;
//单位量,存储一(#`O′维数组时用
ll node[N *10], tot_node = 0;
//因为每有一个点都会影响周围8个以及自身,同时防止问题,我们故意开大点
//tot_node表示一共多少个点受影响

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);

	ll h, w, n;
	cin >> h >> w >> n;
	ll node_zero = (h - 2) * (w - 2);
	//我们先默认所有点都是0,node_zero就表示所有中心点的数量(即所有矩阵的数量)
	int x, y;
	while (n--)
	{
		cin >> x >> y;
		for (int i = -1; i < 2; i++)
			for (int j = -1; j < 2; j++)
			//因为这个点会影响3*3矩阵,所以相邻的中心点也会受影响
			{
				if (2 <= x + i && x + i <= h - 1 && y + j >= 2 && y + j <= w - 1)
				//这个中心点在中心点的范围内,是有效的
				{
					node[tot_node] = e * (x - i) + (y - j);
					//二维点一位化
					tot_node++;
				}
			}
	}

	sort(node, node + tot_node);
	//对所有的点排列,这样相同的点就会靠近在一起(也可以用set)

	for (int i = 0, num = 1; i < tot_node; i++)
	{
		if (node[i] == node[i + 1])num++;
		//表示这个点重复,所以这个中心点的数量+1;
		else
		{
			res[num]++;
			num = 1;
			node_zero--;
		}
		
	}
	cout << node_zero << '\n';
	for (int i = 1; i < 10; i++)
	{
		cout << res[i] << '\n';
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值