题目描述 (NOIP2005普及组第二题)
某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是11米。我们可以把马路看成一个数轴,马路的一端在数轴00的位置,另一端在LL的位置;数轴上的每个整数点,即0,1,2,…,L0,1,2,…,L,都种有一棵树。
由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。
输入输出格式
输入格式:
第一行有22个整数L(1≤L≤10000)和M(1≤M≤100),LL代表马路的长度,M代表区域的数目,L和M之间用一个空格隔开。
接下来的M行每行包含22个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标。
输出格式:
11个整数,表示马路上剩余的树的数目。
输入输出样例
输入样例#1: 输出样例#1:
500 3 298 150 300 100 200 470 471
说明
对于20%的数据,区域之间没有重合的部分;
对于其它的数据,区域之间有重合的情况。
解题策略
1.直接模拟,马路上修建地铁占用的点标记为1,未被占用的点标记为0。
代码如下:
1 #include <bits/stdc++.h> 2 #include <stdlib.h> 3 4 using namespace std; 5 typedef struct { 6 int start, end; 7 } node; 8 9 int main(int argc, const char *argv[]) 10 { 11 int L, M, ans = 0; 12 scanf ("%d%d", &L, &M); 13 int a[L+1]; 14 node aa[M]; 15 memset(a, 0, sizeof(a)); 16 for (int i = 0; i < M; i++) 17 scanf ("%d%d", &aa[i].start, &aa[i].end); 18 for (int i = 0; i < M; i++) { 19 int ss = aa[i].start; 20 int ee = aa[i].end; 21 for (int j = ss; j <= ee; j++) a[j] = 1; 22 } 23 for (int i = 0; i <= L; i++) 24 if (a[i] == 0) ans++; 25 printf ("%d ", ans); 26 return 0; 27 }
但是测试的时候出现了一个问题,关于memset函数。在第15行,将数组a全部赋值为1时
memset(a, 1, sizeof(a));
通过中间结果测试出了问题,发现并没有赋值成功。
如下demo是可以的,能把数组中的元素值都设置成字符1.
1 #include <iostream> 2 #include <cstring> 3 using namespace std; 4 int main() 5 { 6 char a[5]; 7 memset(a,'1',5); 8 for(int i=0;i<5;i++) 9 cout<<a[i]<<""; 10 system("pause"); 11 return 0; 12 }
如下程序想把数组中的元素值设置成1,却是不可行的!
#include <iostream> #include <cstring> #include <windows.h> using namespace std; int main() { int a[5]; memset(a,1,20); //也等价于memset(a,1,sizeof(a)); for(int i=0;i<5;i++) cout<<a[i]<<""; system("pause"); return 0; }
因为第一个程序的数组a是char型的,字符型占据内存大小是1Byte,而memset函数也是以Byte为单位进行赋值的,所以你输出没有问题。而第二个程序a是整型(int)的,使用 memset还是按字节赋值,这样赋值完以后,每个数组元素的值实际上是0x01010101即十进制的16843009。如果用memset(a,1,20),就是对a指向的内存的20个字节进行赋值,每个都用数1去填充,转为二进制后,1就是00000001,占一个字节。一个int元素是4字节,合一起是0000 0001,0000 0001,0000 0001,0000 0001,转化成十六进制就是0x01010101,就等于16843009,就完成了对一个int元素的赋值了。