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;
}