2549. 删除他们!
【问题背景】
Sombra 在很小的时候就表现出了对于电脑的天份。
八个月大的时候,她就能自己爬着过去打开电脑。
四岁的时候就能够正常的使用电脑————多数人的那种正常,打字,翻网页什么的。
六岁的时候,她已经开始学习编程了,之后也参加了一些编程比赛。
八岁,在算法领域玩耍了两年的她,转向了实际应用的领域。
这时,“黑客”这个职业进入了她的视野。
不过这次我们要讲的是 Sombra 小时候的事。
三岁的时候, Sombra 的妈妈教她用电脑。
“Sombra,今天我教你删除文件。”
“这个文件夹中有很多文件,我每次可以框选一些文件,然后按下 Del 键,这样它们就被扔到回收站里去了。”
说着,Sombra 妈妈框选了一些文件,删掉了它们,后面的文件向前补了上来。
“我每次在文件夹里框一下,然后删掉它选中的文件,最后,你告诉我还剩了多少个文件好吗?”
【问题描述】
给一个有 N 行,M 列的文件夹,每个位置上原本都有一个文件。
(行编号从上到下递增,列编号从左到右递增,从 0 开始使用)
Sombra 的妈妈一共会框选并删除 Q 次,
每次用 4 个坐标表示,X1,Y1,X2,Y2,表示框选从第 X1 行,Y1 列开始,一直到第 X2 行,Y2 列,包含边界上的文件。
最后请回答,还剩多少个文件没有被删除。
【输入格式】
输入共 Q+1 行。
第 1 行包含 3 个正整数,N,M,Q,含义如上所述。
第 1 +(1) 至 1 +(Q) 行,每行包含 4 个非负的整数,X1,Y1,X2,Y2,含义如上所述。
【输出格式】
输出共 1 行。
第 1 行包含 1 个非负的整数,表示最后剩余的文件数目。
【样例输入】
2 3 2 0 1 0 2 0 2 1 2
【样例输出】
3
【数据规模与约定】
对于测试点 1 到 3,N <= 10; M <= 10; Q <= 5
对于测试点 4 到 10,Q <= 100
对于全部数据,保证 N*M <= 1,000,000; 0 <= X1 <= X2 < N; 0 <= Y1 <= Y2 < M; Q <= 100
全部数据中的X1,Y1,X2,Y2均为在其合法范围内随机先选出的。
【更多说明】
文件向前补齐规则:
如果文件本行前一列位置处为空,则补到前一列
如果文件位于某行第一个,前一行最后一列位置处为空,则补到前一行末尾 如此循环,直至不能再补为止
(与 Windows 系统的文件夹中删除文件后向前补齐的规则相同)
解题思路:该题删除文件时可以看成直接从后面删,因为删掉的文件还会有后续补上相当于从后删(x2-x1)*(y2-y1)个;所以可以先扫一下x1,x2,y1,y2范围内有多少文件,就从后面删几个文件,div一下再mod一下就行了。但要注意上一次未删完的文件个数,本次应先将mod所得与未删完个数比较,若mod大于未删完个数,将div++,mod=mod-未删完个数再操作。
思路就是这样的,再观察数据,100%的数据是N*M<=1,000,000;可能有人不会搞二维数组的MAXM,MAXN,因为开小会T,开大会M,就是A不了。因此,我们应该记住,看到m*n的数据范围,很多时候应该用一维数组来模拟二维数组,相当于开散列。
代码如下:
#include <cstdio>
using namespace std;
bool mp[1000003];
int N, M, Q;
int S;
void work() {
int X1, Y1, X2, Y2;
scanf("%d %d %d %d", &X1, &Y1, &X2, &Y2);
for (int i = X1; i <= X2; i++)
for (int j = Y1; j <= Y2; j++)
mp[i*M+j] = true;
int lt = 0;
for (int i = 0; i < S; i++)
if (!mp[i])
mp[lt++] = false;
S = lt;
}
int main() {
freopen("deleteit.in", "r", stdin);
freopen("deleteit.out", "w", stdout);
scanf("%d %d %d", &N, &M, &Q);
S = N*M;
for (int i = 0; i < Q; i++)
work();
printf("%d\n", S);
return 0;
}