Java教程

UVA1620 Lazy Susan(结论证明)

本文主要是介绍UVA1620 Lazy Susan(结论证明),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

结论:

当 \(n\geq 6\) 时,若 \(n\) 是奇数且输入序列的逆序对数是奇数,则无解,否则有解。

当 \(n=4\) 或 \(n=5\) 时,答案个数及其有限,只有这个环是 \(1\) 到 \(n\) 的排列(顺时针或逆时针均可,如 \(2,3,4,1\)、\(2,1,4,3\))时有解,否则无解。但因为题目中 \(n\geq 8\) 所以这种情况你无需考虑。

证明:

\(n<6\) 的特殊情况暴搜即可证明,下面不妨假设 \(n\geq 6\)。

首先我们注意到,我们可以对序列 \(1,2,3,4,5,6\),不交换序列首尾交接处的元素把 \(1,2,3,4,5,6\) 变成 \(6,2,3,5,4,1\) 或 \(6,5,3,4,2,1\) 或 \(6,4,5,3,2,1\)。证明不必多说,暴搜即可。

我们可以证明,当 \(n\) 为奇数时,题中操作不会改变序列逆序对数的奇偶性。证明如下:

题目中的操作等价于只对序列进行两种操作:

  • 将前四个元素翻转;
  • 将第一个元素移到末尾。

对于第一种操作,显然前 \(4\) 个元素之一与后面的元素形成的逆序对数不变,后面元素互相形成的逆序对数也不变,只需考虑前 \(4\) 个元素互相形成的逆序对数。设原来此数为 \(x\),则顺序对数为 \(6-x\),翻转后逆序对数即为 \(6-x\),逆序对数变化量为 \(|x-(6-x)|=2|x-3|\) 为偶数,所以操作 \(1\) 不会改变序列逆序对数的奇偶性。

对于第二种操作,假设原来元素 \(1\) 和其他元素形成的逆序对数为 \(y\),则之后该元素和其他元素形成的逆序对数变为 \(n-1-y\),而 \(n\) 是奇数,所以操作 \(2\) 也不会改变序列逆序对数的奇偶性。

由此可知,若 \(n\) 是奇数且输入序列的逆序对数是奇数,则无解。
下面我们证明其他情况必有解:

我们可以先把元素 \(1\) 归位,只要元素 \(1\) 在位置 \(4\),就可以翻转过来。同理只要元素 \(1\) 出现在位置 \(1,4,3,5,2,6\dots\) 任何位置,都可以把元素 \(1\) 归位。可以同理归位元素 \(2\)。然后:

若忽略元素 \(1\)、\(2\) 后有解,则由前面的结论知不忽略是也有解,只要把翻转序列首尾交接处的操作换掉即可。

即把长度为 \(n\) 序列的问题转化为了长度为 \(n-2\) 序列的问题,又因为当 \(n\) 为奇数时操作不会改变逆序对数奇偶性,我们只要证明 \(n=6,7\) 时结论成立即可。

暴力搜索可以验证结论的确成立。综上可得本题结论。

代码:

当然可以用归并排序或树状数组求逆序对数,但本题数据规模小所以不需要。

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int T, n, a[500];
	cin >> T;
	while(T--)
	{
		cin >> n;
		for(int i = 0; i < n; ++i)
			cin >> a[i];
		bool x = true; // 求逆序对数的奇偶性
		if(n & 1)
			for(int i = 0; i < n; ++i)
				for(int j = i+1; j < n; ++j)
					if(a[i] > a[j])
						x = !x;
		puts(x ? "possible" : "impossible");
	}
	return 0;
}

同步于洛谷博客

这篇关于UVA1620 Lazy Susan(结论证明)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!