UVA 12657 - Boxes in a Line

题目大意:给你 N 个数,M 条指令,问当执行完这些指令时,所有在奇数位置上的数的和

解题思路:用链表来模拟,值得注意的是,不能真的去执行反转操作,因为数据量过大,有可能会超时


#include <cstdio>

struct Node {
	int left;
	int right;
};
struct Node node[100010];

void link(int x, int y) //链接相邻的两个元素
{
	node[y].left = x;
	node[x].right = y;
}

void moveleft(int x, int y) //  1 x 3 y 5  -->  1 3 x y 5
{
	//把 x 移出序列
	link(node[x].left, node[x].right); 
	//把 x 插入到 y 的前面
	link(node[y].left, x);
	link(x, y);
}

void moveright(int x, int y) // 1 x 3 y 5  -->  1 3 y x 5
{
	//把 x 移出序列
	link(node[x].left, node[x].right);
	//把 x 插入到 y的后面
	link(x, node[y].right);
	link(y, x);
}

void exchange(int x, int y) //对调 x 与 y 位置
{
	struct Node X, Y; //记录下 x, y 的位置, 避免互换位置的过程中 x, y 之前所在的位置的信息, 因 x, y 的位置的改变而改变
	X.left = node[x].left;
	X.right = node[x].right;
	Y.left = node[y].left;
	Y.right = node[y].right;

	if (node[x].right == y) // x y 相邻的情况:  x y  -->  y x 
	{
		link(X.left, y);
		link(y, x);
		link(x, Y.right);
	}
	else if (node[y].right == x) // y x 相邻的情况:  y x  -->  x y 
	{
		link(Y.left, x);
		link(x, y);
		link(y, X.right);
	}
	else // x y 不相邻的情况:1 x 3 y 5  -->  1 y 3 x 5
	{
		// 让 y 占据 x 的位置 
		link(X.left, y);
		link(y, X.right);
		// 让 x 占据 y 的位置 
		link(Y.left, x);
		link(x, Y.right);
	}
}


int main() {
	int n, m, t = 0;
	while (scanf("%d%d", &n, &m) != EOF) {
		for (int i = 0; i <= n; i++)	//初始化链表 数字的范围是 1 ~ n , 但我们要做成 0 ~ n + 1 的链表 
			link(i, i + 1);				//这是为了避免 1 的左边、n 的右边没有元素所引发的问题

		int change = 0;
		for (int i = 0; i < m; i++) { //执行 m 条指令
			int x, y, command;
			scanf("%d",&command);

			if (command == 4)	//当指令为 4 时我们不能真的去执行反转链表的操作, 因为操作量太大,有可能超时
				change++;       //实际上我们也不需要真的执行,只需记录反转的次数,并根据反转次数, 对指令 1 和 2 做反转处理即可 
			else {
				scanf("%d%d", &x, &y);
				if (change % 2 != 0 && command != 3)	//反转链表奇数次, 就反转指令 1 和 2, 反转链表不影响指令 3
					command = 3 - command;				//反转链表偶数次,不会对任何的指令的执行造成影响
				if (command == 1)
					moveleft(x, y);
				if (command == 2)
					moveright(x, y);
				if (command == 3)
					exchange(x, y);
			}
		}

		int flag = 1, position = 1;
		long long sum = 0; //结果可能超过 int 的范围

		//如果是 n 是奇数或者反转次数是偶数,则不管反转多少次,奇数位置的数还是在奇数位置
		if (n % 2 == 0 && change % 2 == 1)	//如果是 n 的偶数, 且反转次数是奇数次,奇数位置的数在偶数位置上 
			flag = 0;


		//求 1 ~ n 里面所有在奇数位置上的数的和
		for (int i = node[0].right; position <= n; i = node[i].right) {
			if (position % 2 == flag) //判断是求所有奇数位置的数的和,还是求所有偶数位置的的数的和
				sum += i;
			position++;
		}
		printf("Case %d: %lld\n", ++t, sum);
	}
	return 0;
}

你可能感兴趣的:(UVA 12657 - Boxes in a Line)