题解:[ARC122E] Increasing LCMs
题意分析
对于这种构造题,构造一组 \(x_1,x_2,\cdots,x_n\),\(x_i\) 受到前缀信息限制,可以考虑倒序从后往前构造。
则 \(a_i\) 能放在末尾,记 \(A\) 为除 \(a_i\) 外未放置的集合,当且仅当:
\[\begin{aligned}
\operatorname*{lcm}_{x\in A}x&<\operatorname{lcm}\left(\operatorname*{lcm}_{x\in A}x,a_i\right)\\
\operatorname*{lcm}_{x\in A}x&<\dfrac{\displaystyle a_i\operatorname*{lcm}_{x\in A}x}{\displaystyle\operatorname{gcd}\left(\operatorname*{lcm}_{x\in A}x,a_i\right)}\\
a_i&>\gcd\left(\operatorname*{lcm}_{x\in A}x,a_i\right)\\
\end{aligned}
\]
但是这个东西还是不太好做,因为求 \(\displaystyle\operatorname*{lcm}_{x\in A}x\) 会爆 long long。将其转化为:
\[a_i>\gcd\left(\operatorname*{lcm}_{x\in A}x,a_i\right)=\operatorname*{lcm}_{x\in A}\gcd(x,a_i)
\]
根据唯一分解定理,这是正确的。
之后当 \(A\) 中删除元素的时候,\(\displaystyle\operatorname*{lcm}_{x\in A}x\) 单调不升,\(a_i\) 一定时 \(\displaystyle\gcd\left(\operatorname*{lcm}_{x\in A}x,a_i\right)\) 也单调不升。因此这个做法是正确的,任意选取满足条件的 \(a_i\) 构造即可。
于是可以暴力 \(\mathcal O\left(n^3\log V\right)\) 构造,无解就是当前找不到一个 \(a_i\) 使得 \(\displaystyle a_i>\operatorname*{lcm}_{x\in A}\gcd(x,a_i)\) 成立。
AC 代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
typedef long long ll;
constexpr const int N=100;
int n;
ll a[N+1],x[N+1];
bool vis[N+1];
ll lcm(ll a,ll b){
return a/__gcd(a,b)*b;
}
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=n;i>=1;i--){
for(int j=1;j<=n;j++){
if(vis[j]){
continue;
}
ll pl=1;
for(int k=1;k<=n;k++){
if(vis[k]||j==k){
continue;
}
pl=lcm(pl,__gcd(a[j],a[k]));
}
if(pl<a[j]){
x[i]=a[j];
vis[j]=true;
break;
}
}
if(x[i]==0){
cout<<"No\n";
return 0;
}
}
cout<<"Yes\n";
for(int i=1;i<=n;i++){
cout<<x[i]<<' ';
}
cout.flush();
/*fclose(stdin);114514
fclose(stdout);*/
return 0;
}

浙公网安备 33010602011771号