【ARC122E】Increasing LCMs
题目
题目链接:https://atcoder.jp/contests/arc122/tasks/arc122_e
给定一个长度为 \(n\) 的正整数序列 \(a\),要求重排 \(a\) 中的元素,记 \(b_i\) 为重排后 \(\text{lcm}(a_1,a_2,\cdots,a_i)\),要求 \(b_1<b_2<\cdots<b_n\)。
给出一个合法的重排方案。
\(n\leq 100;a_i\leq 10^{18}\)。
思路
考虑最后一位的数字。假设填 \(a_i\),显然必须满足 \(\text{gcd}(a_i,\text{lcm}_{i\neq j}(a_j))\neq a_i\)。
那么从后往前不断确定最后一位数字即可。因为如果一个数字可以填在第 \(i\) 位,那么显然也可以填在第 \(j(j<i)\) 位。
时间复杂度 \(O(n^3\log a)\)。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=110;
int n;
ll a[N],b[N],g[N][N];
bool used[N];
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b)
{
return a/gcd(a,b)*b;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%lld",&a[i]);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
g[i][j]=gcd(a[i],a[j]);
for (int i=n;i>=1;i--)
{
bool flag=0;
for (int j=1;j<=n;j++)
if (!used[j])
{
ll l=1;
for (int k=1;k<=n;k++)
if (!used[k] && j!=k)
l=lcm(l,g[j][k]);
if (l<a[j])
{
b[i]=a[j]; used[j]=1;
flag=1; break;
}
}
if (!flag) return printf("No"),0;
}
printf("Yes\n");
for (int i=1;i<=n;i++)
printf("%lld ",b[i]);
return 0;
}