题目链接
https://codeforces.com/problemset/problem/1401/C
题目描述
有一列正整数: a 1 , a 2 , … , a n a_1,a_2,\dots,a_n a1,a2,…,an,每次操作,你可以选择 1 ≤ i , j ≤ n 1\le i,j\le n 1≤i,j≤n,如果 gcd ( a i , a j ) \gcd(a_i,a_j) gcd(ai,aj) 等于整个数组中最小的元素,你就可以交换 a i a_i ai 和 a j a_j aj,其中 gcd ( x , y ) \gcd(x,y) gcd(x,y) 表示 x x x 和 y y y 的最大公因数。
你可以进行任意数量的操作,请判断能否通过这些操作使得 a a a 变为不下降序列。
a a a 称为不下降序列,当且仅当 a 1 ≤ a 2 ≤ ⋯ ≤ n a_1\le a_2\le\dots\le n a1≤a2≤⋯≤n。
解题思路
设最小公元素为 d d d.
- 对序列进行排序,只交换顺序错乱的元素;
- 判断这些需要交换的数能否整除 d d d,能则是合法元素,否则无法交换,输出“NO”;
- 至于为什么只需要判断能否整除
d
d
d,而无需求最大公约数?原因是所有数交换时可以以
d
d
d为桥梁,比如下面的例子,
d
=
3
d=3
d=3,原始序列为
12
,
3
,
6
12,3,6
12,3,6,
12
12
12不需要和
6
6
6进行交换,只需以
3
3
3为桥梁交换至正确的位置即可。
12,3,6
12,6,3
3,6,12
参考代码
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
const int MAXN=100006;
int a[MAXN],b[MAXN];
int main(){
int t,n;
scanf("%d",&t);
while( t-- ){
int min_val=1e9+3;
scanf("%d", &n);
for(int i=1; i<=n; i++) {
scanf("%d", &a[i]);
b[i] = a[i];
min_val = min( min_val, a[i] );
}
bool flag = true;
sort(a+1,a+1+n);
for(int i=1; i<=n; i++)
if( a[i]!=b[i] && b[i] % min_val){
flag = false;
break;
}
if( flag ) printf("YES\n");
else printf("NO\n");
}
return 0;
}