【题解】CF2039D Shohag Loves GCD
思路(贪心 + 唯一分解定理)
这个题其实只需要考虑一件事:记答案数组为
证明:任意两个数
第一种情况,如果
第二种情况,如果
证毕。
答案要最大字典序,那首先就把原集合元素从大到小排列来贪心求解。
对
因为除掉的数越少,前置下标包含的因子一定越多,求得的答案肯定越能满足前面所有的下标。
所以只需要对每一个答案数组下标用除掉一个素数的前置下标来转移就行了。
我们用
而这个过程可以直接预处理,因为我们只需要得到每一个答案数组的下标对应的一个集合内部的下标。
时间复杂度:
AC CODE
#include <bits/stdc++.h>
#define int long long
#define inf 2e18
#define ull unsigned long long
#define ls o << 1
#define rs o << 1 | 1
using namespace std;
const int N = 1e5 + 9;
int a[N];
int ans[N];
int n, m;
bool check()
{
for(int i = 1;i <= n;i ++)
if(ans[i] > m)return false;//只要下标超出了集合的大小,就无解
return true;
}
void solve()
{
cin >> n >> m;
for(int i = 1;i <= m;i ++)cin >> a[i];
reverse(a + 1, a + m + 1);//将集合元素从大到小排列
if(check())
{
for(int i = 1;i <= n;i ++)cout << a[ans[i]] << " \n"[i == n];
}
else cout << -1 << '\n';
}
void init()//预处理每个答案数组的下标对应的集合下标
{
ans[1] = 1;
for(int i = 2;i < N;i ++)
{
int tmp = i;
for(int j = 2;j * j <= tmp;j ++)
{
if(tmp % j == 0)
{
ans[i] = max(ans[i], ans[i / j] + 1);
while(tmp % j == 0)tmp /= j;
}
}
if(tmp > 1)ans[i] = max(ans[i], ans[i / tmp] + 1);
}
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
init();
int t = 1;cin >> t;
while(t --)solve();
return 0;
}
作者: 天天超方的
出处: https://www.cnblogs.com/TianTianChaoFangDe
关于作者:ACMer,算法竞赛爱好者
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显醒目位置给出, 原文链接 如有问题, 可邮件(1005333612@qq.com)咨询.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架