第一种:暴力破解
for(i:1~M)
for(j:区间长度)
对于本题数据L(1 <= L <= 10000)和 M(1 <= M <= 100),时间复杂度最大为O(M*L),可以ac;
但如果数据范围扩大,此方法则行不通。
第二种:差分记录每个点被区域覆盖的次数,覆盖0次的点则有树。
#include<iostream> using namespace std; int delta[10010]; //差分:记录每一个点与前一个点上区域覆盖的次数之差, //其值表示当前点被区域覆盖的次数 int main(){ int l; //马路的长度 int m; //区域的数目 cin >> l >> m; for(int i = 0; i < m; i++){ int start, end; cin >> start >> end; if(start <= end){//当起始点 <= 终止点时 delta[start]++; //起始点比其前一个点多被覆盖一次 delta[end+1]--; //终止点的后一个点比终止点少被覆盖一次 } else{ delta[end]++; delta[start+1]--; } } int sum = 0; //树的数目总和 int a = 0; //记录当前点被区域覆盖的次数 for(int i = 0; i <= l; i++){ a += delta[i]; if(a == 0){ sum++; } } cout << sum <<endl; return 0; }第三种:将各区域按起始端点从大到小进行排序,合并有交集的区域,再计算减去每块区域移走树木的数量。
#include<iostream> #include<algorithm> using namespace std; struct area{ int start; int end; }a[110]; bool comp(area a, area b){ if(a.start < b.start) return 1; else return 0; } int main(){ int l, m; cin >> l >> m; for(int i = 0; i < m; i++){ cin >> a[i].start >> a[i].end; } sort(a, a + m, comp); //将区域按照起始端点从左到右排序 int left = a[0].start; //记录一个区域的左端点 int right = a[0].end; //记录一个区域的右端点 int cnt = l + 1; //刚开始有l+1棵树 for(int i = 1; i < m; i++){ if(a[i].start < right){//当前区域与上一区域有交集 right = max(right, a[i].end); } else{//当前区域与上一区域无交集 cnt -= right - left + 1; //减去上一个连续的区域中移走的树 left = a[i].start; //更新当前区域端点值 right = a[i].end; } } //考虑最后一个区域的情况 cnt -= right - left + 1; cout << cnt << endl; }第四种:创建结构体,只维护端点的位置和端点的差分值,a += delta[i] 当a == 0时,i为每个不连续的区域起始点的前一个点,则 (a == 1 && delta[i] == 1) i为每个不连续的区域的起始点。由此可以计算出树的数量,记得要加上最后一个终止点到路尽头的树。
#include<iostream> #include<algorithm> using namespace std; struct area{ int pos; //区域端点的位置 int num; //区域端点与前一个点的差值 }delta[220]; bool comp(area a, area b){ if(a.pos < b.pos) return 1; else return 0; } int main(){ int l, m; cin >> l >> m; int start, end; for(int i = 0; i < m; i++){//维护每个端点的差分值,起始点则+1,终止点的下一个点则-1 cin >> start >> end; delta[i].pos = start; delta[i].num = 1; delta[i+m].pos = end + 1; delta[i+m].num = -1; } sort(delta, delta+2*m, comp); //将结构体中维护的端点从左到右排序 int a = 0; //记录当前点的状态 int cnt = 0; //记录树的数量 for(int i = 0; i < 2*m; i++){ a += delta[i].num; // if(a == 1 && delta[i].num == 1){//当前点为区域的起始点 cnt += delta[i].pos - delta[i-1].pos; //区域起始点 - 上一个区域终止点的下一个点 = 树的数量 } } //考虑最后一个端点到路尽头的情况 cnt += l - delta[2*m-1].pos + 1; cout << cnt << endl; }