AtCoder 2068 すぬけ君の塗り絵 / Snuke's Coloring

AtCoder 2068 すぬけ君の塗り絵 / Snuke’s Coloring

Problem Statement
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≤109
3≤W≤109
0≤N≤min(105,H×W)
1≤ai≤H (1≤i≤N)
1≤b~i·≤W (1≤i≤N)
(ai,bi)≠(aj,bj) (i≠j)

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

Output
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.

Sample Input 1
4 5 8
1 1
1 4
1 5
2 3
3 1
3 2
3 4
4 4

Sample Output 1
0
0
0
2
4
0
0
0
0
0

在这里插入图片描述
题意
有一个H行W列的网格,起初都是白色,把N个坐标已知的方格涂成黑色。问,此番操作之后,网格中有多少3×3大小的子矩形正好包含j个黑色单元格(0<=j<=9)?

分析
首先看H,W范围,1e9,趁早打消暴力的念头,连二维数组都开不了,更别提模拟了。
当然,不可能有那么简单的题目的。
再看N的范围,1e5,貌似是个可接受范围,是个很好的入手点,从数据范围大致可以看出出题者的意图,让我们从各个点进行突破。
按照暴力的思路,应该是遍历每个3X3子矩形中心点,然后算九宫格内黑色格子个数。我们不妨反向思考一下,从各个点入手,计算其对每个子矩形的贡献,每个黑色点对周围9个子矩形(包括以黑色点自身为中心的矩形)贡献为1。9*1e5的计算量,完全不得慌。但是如何表示数据又成了一个过不去的坎。
数据表示
如果以坐标为索引,值为以该坐标为中心的子矩形上黑色点的个数,那么首先二维数组开不了,不过可以把二维坐标压成一维,也就是把坐标(a,b)看作(1e9+7)进制的ab,转化为十进制就是a×(1e9+7)+b,用long long 可以存下(为什么是1e9+7不是1e9?大家习惯用素数,我也不是很清楚呀),不过呢,转化之后依然没有什么卵用,一维数组也开不了并且中间有许多空洞(浪费)。那么,怎么办呢?
山穷水复疑无路,船到桥头自然沉。
不妨再次反向思维一下,把压成一维之后的坐标用作[值]而非[索引],岂不美哉。
[索引]则用点加入的次序来表示,开1e6+5的数组足够了。
最后只要统计同一个点被加入数组几次,就可以计算以该点为中心的子矩阵包含几个黑色方格,此步骤可以通过sort简化。
OK,废话不多说。
"Talk is Cheap.Show me the Code"

#include<stdio.h>
#include<algorithm>
using namespace std;
#define INF (int(1e9)+7)//1e9+7进制
#define maxn (int(1e6)+5)
typedef long long ll;
ll node[maxn];
ll res[15];
int main(void)
{
	ll H, W, N;
	scanf("%lld %lld %lld", &H, &W, &N);
	int cnt = 0;
	while (N--)
	{
		ll a, b;
		scanf("%lld %lld", &a, &b);
		for (int i = -1; i <= 1; i++)
			for (int j = -1; j <= 1; j++)
				if (a + i >= 2 && a + i <= H - 1 && b + j >= 2 && b + j <= W - 1)
					node[cnt++] = (a + i) * INF + (b + j);//1e9+7进制转换
	}
	sort(node, node + cnt);
	ll temp = node[0];
	ll sum = 1;
	for (int i = 1; i < cnt; i++) {
		if (node[i] == temp)
			sum++;
		else
			res[sum]++, sum = 1, temp = node[i];
	}
	if(cnt)res[sum]++;
	res[0] = (H - 2) * (W - 2);
	for (int i = 1; i <= 9; i++)
		res[0] -= res[i];
	for (int i = 0; i <= 9; i++)
		printf("%lld\n", res[i]);
	return 0;
}
发布了4 篇原创文章 · 获赞 1 · 访问量 108

猜你喜欢

转载自blog.csdn.net/qq_33374268/article/details/104284342
今日推荐