东华oj-进阶题26题

26 树

作者: ZhuKai时间限制: 10S章节: 一维数组

问题描述 :

明明是一家地铁建设公司的职员,他负责地铁线路的规划和设计。一次,明明要在一条长L的马路上建造若干个地铁车站。

这条马路有一个特点,马路上种了一排树,每两棵相邻的树之间的间隔都是一米。

如果把马路看成一个数轴,马路的一端在数轴0的位置,马路的另一端在L的位置,那么这些树都种在数轴的整数点上,即0,1,2,…,L上都种有一棵树。

由于要设计建造地铁站的缘故,所以需要把一些树移走,明明为了移树的方便,把地铁站的区域也建在了数轴上两个整数点之间,由于有多条地铁线路,地铁车站的区域可能会有部分的重合(重合的区域明明将来会设计成一个大型的车站,移树的时候不必考虑地铁站重合区域的问题)。

现在明明想请你帮一个忙,他把车站区域的位置告诉你,即告诉你数轴上的两个整数点,在这两个整数点之间是车站的区域,请你写一个程序,计算出把所有车站区域两点之间的树移走以后,这条马路上还剩多少棵树。

例如:马路长为10,要建造2个地铁车站,车站的区域分别是2到5和3到6,原先的马路上一共有11棵树,在2到5的位置上建车站后,需要移走4棵树,在3到6的位置上建车站后,也需要移走4棵树,但是3到6这个区域和2到5这个区域有部分重合,所以只需移走1棵树即可,这样总共移走的树是5棵,剩下的树就是6棵。

明明的问题可以归结为:给你一条马路的长度和若干个车站的位置,请你用程序计算出把树移走后,马路上还剩多少棵树。 输入说明 :

你写的程序要求从标准输入设备中读入测试数据作为你所写程序的输入数据。标准输入设备中有多组测试数据,每组测试数据有多行,每组测试数据的第一行有两个整数L(1≤L≤10000)和M(0≤M≤100),分别表示马路的长度和地铁车站区域的个数。接下来有M行,每行有2个整数,分别表示每一座地铁车站区域的两个坐标的。每组测试数据与其后一组测试数据之间没有任何空行,第一组测试数据前面以及最后一组测试数据后面也都没有任何空行。
输出说明 :

对于每一组测试数据,你写的程序要求计算出一组相应的运算结果,并将每组运算结果作为你所写程序的输出数据依次写入到标准输出设备中。每组运算结果为一个整数,即把树移走后,马路上还剩下多少棵树。每组运算结果单独占一行,其行首和行尾都没有任何空格或其他任何字符,每组运算结果与其后一组运算结果之间没有任何空行或其他任何字符,第一组运算结果前面以及最后一组运算结果后面也都没有任何空行或其他任何字符。
注:通常,显示屏为标准输出设备。 输入范例 : 5 1 1 2 10 2 2 5 3 6 输出范例 : 4 6

刚一看到感觉这是个青铜题,好简单哈哈,没想到做到后面发现其实是个王者题……
在这里插入图片描述
第三种情况卡了我好久……
代码:

/*
	树 
	算法概述:先排序,然后将被覆盖的区域全部去掉,
	再按照没有重叠算出需移走的树,然后处理重叠的区域 
*/

#include<stdio.h>
#define MAX_SIZE 101

// 车站起始点的坐标 
typedef struct staPoint {
	int start;
	int  end; 
} staPoint;

void sort(staPoint points[], int n);

int main() {
	int L = 0, M = 0;
	int i = 0, j = 0, k = 0; 
	int movedTrees = 0;// 被移走的树 
	staPoint points[MAX_SIZE];
	
	scanf("%d%d", &L, &M);
	for (i = 0; i < M; i++) {
		scanf("%d%d", &points[i].start, &points[i].end);
	} 
	sort(points, M);// 排序,保证某一个区域在下一个区域之前
	
	// 将某个区域中覆盖的其他区域都删掉(如果存在的话) 
	for (i = 0; i < M - 1; i++) {
		for (j = i + 1; j < M; ) {
			if ((points[i].start <= points[j].start) && 
			(points[i].end >= points[j].end)) {
				for (k = j; k < M - 1; k++) {
					points[k] = points[k + 1];
				}
				M--;
			} 
			else {
				j++;
			} 
		}
	} 
	
	for (i = 0; i < M; i++) {
		movedTrees += (points[i].end - points[i].start + 1);
	} 
	
	for (i = 0; i < M - 1; i++) {
		if (points[i].end >= points[i + 1].start) {// 前后两区域有重合 
			movedTrees -= (points[i].end - points[i + 1].start + 1); 
		}
	}
	
	printf("%d\n", L - movedTrees + 1); 
	
	return 0;
} 

// 排序函数 
void sort(staPoint points[], int n) {
	int i = 0, j = 0;
	staPoint temp;

	for (i = n - 1; i >= 0; i--) {
		for (j = 0; j < i; j++) {
			if (points[j].start > points[j + 1].start) {
				temp = points[j];
				points[j] = points[j + 1];
				points[j + 1] = temp;
			}
		}
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一道经典的位运算目,考察对二进制的理解和位运算的熟练程度。 目描述: 给定一个度为 $n$ 的数组 $a$,初始时每个数的值都为 $0$。现在有 $m$ 个操作,每个操作为一次询问或修改。 对于询问,给出两个整数 $l,r$,求 $a_l \oplus a_{l+1} \oplus \cdots \oplus a_r$ 的值。 对于修改,给出一个整数 $x$,表示将 $a_x$ 的值加 $1$。 输入格式: 第一行两个整数 $n,m$。 接下来 $m$ 行,每行描述一次操作,格式如下: 1 l r:表示询问区间 $[l,r]$ 的异或和。 2 x:表示将 $a_x$ 的值加 $1$。 输出格式: 对于每个询问操作,输出一个整数表示答案,每个答案占一行。 数据范围: $1 \leq n,m \leq 10^5$,$0 \leq a_i \leq 2^{30}$,$1 \leq l \leq r \leq n$,$1 \leq x \leq n$ 输入样例: 5 5 2 1 2 3 1 2 4 2 2 1 1 5 输出样例: 0 2 解思路: 对于询问操作,可以利用异或的性质,即 $a \oplus b \oplus a = b$,将 $a_l \oplus a_{l+1} \oplus \cdots \oplus a_r$ 转化为 $(a_1 \oplus \cdots \oplus a_{l-1}) \oplus (a_1 \oplus \cdots \oplus a_r)$,因为两个前缀异或后的结果可以相互抵消,最后的结果即为 $a_1 \oplus \cdots \oplus a_{l-1} \oplus a_1 \oplus \cdots \oplus a_r = a_l \oplus \cdots \oplus a_r$。 对于修改操作,可以将 $a_x$ 对应的二进制数的每一位都分离出来,然后对应位置进行修改即可。由于只有加 $1$ 操作,所以只需将最后一位加 $1$ 即可,其余位不变。 参考代码:

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值