CF1401-C. Mere Array

CF1401-C. Mere Array

题意:

给出一个长度为\(n\)的数组\(a\),你可以对这个数组进行如下操作:对于数组\(a\)中任意的两个元素\(a_i\)\(a_j\),若\(gcd(a_i,a_j)=min\{a_1,a_2,...,a_n\}\),那么就可以交换数组中的这两个数字。

现在问你是否能够通过一定次的上述操作使得数组\(a\)变成非递减序列。


思路:

首先,由于\(min\{a_1,a_2,...,a_n\}\)是定值,那么对于任何数字\(a_i\),只要\(a_i\)\(a_{min}\)的倍数,都可以构成\(gcd(a_i,a_{min})=a_{min}\),换句话说只要\(a_i\)\(a_{min}\)的倍数,\(a_i\)\(a_{min}\)都是可以随意交换的。反之,如果\(a_i\)不是\(a_{min}\)的倍数,那么数字\(a_i\)无论如何都不可能被移动,原因在于:既然\(a_i\)不是\(a_{min}\)的倍数,那么对\(a_i\)进行分解必然不可能得到\(a_{min}\),那么\(a_i\)与任何其他数字\(a_j\)的公因数都不可能分解出\(a_{min}\),那么\(gcd(a_i,a_j)\)也就不可能等于\(a_{min}\)了。

其次,将数组\(a\)进行排序可以得到数组\(b\),那么如果\(b[i]\not=a[i]\)那必然是通过交换数字得到的,而交换数字就可以通过上面说到的方式进行交换。对所有的\(b[i]\not=a[i]\),若\(a[i]\%a_{min}\)都等于\(0\),那么就可以通过题目给出的操作的到非递减序列\(b\),否则不可以。

对于上面一条不理解的可以这样想,我们把序列中\(a[i]\not=b[i]\)的数字\(a[i]\)以及\(a_{min}\)保留下来,然后用\(a_{min}\)作为临时变量对剩下的序列进行选择排序,必然可以使得这个序列变成非递减序列,让后再把删除的数字加进去就可以得到数组\(b\)。删与不删本质上都是一样的,只是为了更好地理解。


AC代码

#include <cstdio>
#include <cstring>
#include <algorithm>

const int INF = 0x3f3f3f3f;
const int Maxn = 100005;

int a[Maxn], b[Maxn];

void solve() {
	int n, minn = INF;
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		scanf("%d", a + i);
		minn = std::min(minn, a[i]);
	}
	memcpy(b, a, sizeof a);
	std::sort(b, b + n);
	bool flag = true;
	for (int i = 0; i < n; i++) {
		if (a[i] != b[i] && a[i] % minn != 0) {
			flag = false;
			break;
		}
	}
	printf("%s\n", flag ? "YES" : "NO");
}

int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

posted @ 2021-01-27 17:43  牟翔宇  阅读(70)  评论(0编辑  收藏  举报