校门外的树
Time Limit: 1000 ms
Memory Limit: 65535 kB
Description
某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米。我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置;数轴上的每个整数点,即0,1,2,……,L,都种有一棵树。
马路上有一些区域要用来建地铁,这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。
Input
输入的第一行有两个整数L(1 <= L <= 10,000)和 M(1 <= M <= 100),L代表马路的长度,M代表区域的数目,L和M之间用一个空格隔开。接下来的M行每行包含两个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标。
Output
输出包括一行,这一行只包含一个整数,表示马路上剩余的树的数目。
Sample Input
500 3
150 300
100 200
470 471
Sample Output
298
Source
UESTC
#include <cstdio>
#include <cstring>
const int max_n = 10010;
int main()
{
int L, m, a, b,ans, flag[max_n];
FILE * fin, * fout;
fin = fopen("2.std.in", "r");
fout = fopen("2.std.out", "w");
fscanf(fin, "%d %d", &L, &m);
//printf("%d %d\n", L, m);
memset(flag, 0, sizeof(flag));
while (m--)
{
fscanf(fin, "%d %d", &a, &b);
ans = a > b ? a : b;
a = a + b - ans;
b = ans;
for (int i = a; i <= b; i++)
{
flag[i] = 1;
}
}
ans = 0;
for (int i = 0; i <= L; i++)
{
if (!flag[i])
{
ans++;
}
}
printf("%d\n", ans);
fprintf(fout, "%d\n", ans);
//fclose(fin);
//fclose(fout);
return 0;
}
#include <cstdio>
#include <cstring>
const int max_n = 1000010;
int flag[max_n];
int main()
{
int L, m, a, b, ans, cnt;
FILE * fin, *fout;
fin = fopen("2.std.in", "r");
//fout = fopen("2.out", "w");
fscanf(fin, "%d %d", &L, &m);
memset(flag, 0, sizeof(flag));
while (m--)
{
fscanf(fin, "%d %d", &a, &b);
ans = a > b ? a : b;
a = a + b - ans;
b = ans;
flag[a]++;
flag[b + 1]--;
}
ans = 0;
cnt = 0;
for (int i = 0; i <= L; ++i)
{
cnt += flag[i];
if (cnt == 0)
{
ans++;
}
}
printf("%d\n", ans);
//fclose(fin);
//fclose(fout);
return 0;
}
方法(1):模拟,开一个数组标志树是否被移走,遍历每个区间,将区间上的每个数字赋为1(代表移走)。
方法(2):模拟,同样开一个数组标志是否被移走(0表示未被移走),将每个区间的起点对应得数组元素++,终点后面的数组元素--,最终遍历[0,L]区间,ans为前n项的和,若ans为0,则表示该下标的元素代表的树未被移走,这适合区间较多(n很大),L比较小的情况。
方法(3):当L很大时,将起点和终点排序,然后离散化(只保存对我们有用的(即在数组中出现的点))为一个结构体数组,结构体中一个元素代表下标,一个用来标记,然后借助方法(2)的思想,同样可以得到解。
这样无论L和n的取值在哪个范围内,都可以得到相应的解。