[ARC122E] Increasing LCMs【归纳构造】

[ARC122E] Increasing LCMs

给定序列 a,构造一种重新排序的方案使得其前缀 LCM 严格递增。

考虑归纳构造(倒序构造)

n=1 显然成立。

对于 n>1,我们考虑任意找出这个序列的最后一个数,满足题目要求 lcm(aj)<lcm(lcm(aj),ai),ji,就选择其作为当前序列最后一项,问题变成一个 n1 的子问题。

引理: 一个序列合法,那么其任意子序列都合法。

很好感性理解,理性证明的话,考虑 lcm 的实质是质因数分解后,对一串底数的指数取 max,也就是说合法序列中每一个 i>1 的位置,其至少有一个质因数的指数是其前缀 max,前缀 max 单调不降,所以删掉可以保证后面依旧合法。

回到原问题,我们要证明这样任意选择,不会使得答案的总数减少。考虑一个可能成为最终答案的答案,满足最后一项不是 ai,那么把 ai 删掉,根据引理可得此时依旧合法,变成一个大小为 n1 的子问题,再从后面加上 ai,根据构造规则这样依旧合法。

经典套路: 求一串数的 lcm 常常因为太大无法保存,如果值域较小可以存质因数的指数,但本题值域高达 1018,需要转换条件:ai 存在一个严格最大指数,而 gcd 相当于取 min,因此转换为 lcm(gcd(ai,aj))<ai

#include <bits/stdc++.h>
#define int long long
#define pii pair<int,int>
#define fi first
#define se second
using namespace std;
int read(){
	char c=getchar();int h=0,tag=1;
	while(!isdigit(c)) tag=(c=='-'?-1:1),c=getchar();
	while(isdigit(c)) h=(h<<1)+(h<<3)+(c^48),c=getchar();
	return h*tag;
}
void fil(){
	freopen("data.in","r",stdin);
	freopen("data.out","w",stdout);
}
const int N=105;
int a[N],b[N];
int lcm(int a,int b){
	return a/__gcd(a,b)*b;
}
void work(int n) {
	if(n==1) {
		b[1]=a[1];
		return ;
	}
	for(int i=1;i<=n;i++) {
		int res=1;
		for(int j=1;j<=n;j++) {
			if(i==j) continue;
			res=lcm(res,__gcd(a[i],a[j]));
		}		
		if(res<a[i]) {
			b[n]=a[i];
			for(int j=i;j<=n-1;j++) a[j]=a[j+1];
			work(n-1);
			return ;
		}
	}
}
signed main(){
//	fil();
	int n=read();
	for(int i=1;i<=n;i++) a[i]=read();
	work(n);
	if(b[1]) {
		puts("Yes");
		for(int i=1;i<=n;i++) cout<<b[i]<<" ";
		cout<<endl;
		return 0;
	}
	puts("No");
	return 0;
}

posted @   Apricity8211  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示