【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;
}
posted @ 2021-06-13 10:55  stoorz  阅读(156)  评论(0编辑  收藏  举报