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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章