[刷题笔记] Luogu P9345 夕阳西下几时回
Description
给定一个整数\(n\),有一个数组\(a\)的内容是\(1,2,3\)……\(n\)。(不一定按照顺序排列,只保证内容)特别地,我们令\(a_{n+1}=1\)。
还有一个数组\(b\),满足\(b_i=gcd(a_i,a_{i+1})\) (\(gcd(a,b)\)为\(a\)和\(b\)的最大公约数)
给定一个整数\(k\),试构造出一种排列使得\(b\)数组中不同的数字数量为\(k\)个。如果不存在直接输出No即可,无需输出排列。
Analysis
结论题。
首先一个结论,\(b\)数组中最多有\(⌊\frac{n}{2}⌋\)不同的数字。
证明:由于\(\forall a_i \in[1,n]\)且内容不重复,\(a\)的大小为\(n\),因此对于\(\forall a_i,\forall a_j\)最大公约数最大为\(⌊\frac{n}{2}⌋\)。如果最大公约数超过\(⌊\frac{n}{2}⌋\)则一定不满足\(\forall a_i \in[1,n]\)。得证。
那么第一问就解决了,判断是否\(k\leq ⌊\frac{n}{2}⌋\)即可。
接下来如何构造呢?
我们先忽略有\(k\)个不同的数字,考虑如何最大化也就是有\(⌊\frac{n}{2}⌋\)个不同数字的时候如何构造。
由于\(gcd\)是取相邻的两数,我们肯定要尽可能的使一个数和她的倍数相邻。举个例子,如果\(n=6\)则\(1,2,4,3,6\)这样的构造方式显然是最优的。
到这里我们已经有了一个初步的思路,那么如何去重呢?也就是构造的时候不能出现重复的数字。
这很简单,我们可以先跑一遍2的整次幂,然后再枚举奇数的倍数进行构造。显然奇数的倍数一定不是二的整次幂。这样我们就实现了去重。
那么从奇数开始不断\(\times 2\)有没有可能重复呢?
显然不会。因为一个数字(除了刚开始的奇数)一定是由上一个数字数字\(\times 2\)扩散来的,而同理上一个数字一定是由上一个数字\(\times 2\)得到的......容易发现一个数字可以被哪个奇数扩散到是唯一的。所以不会重复。证毕。
其实到这里我们就已经可以解决CF的问题了:CF1858C
和Luogu重题了被CN选手骂但还是rated了,回复No comment/cf
接下来考虑构造\(k\)个不同的数字。
构造\(k\)个不同的数字我们只需要操作到\(k\times 2\)就可以了。至于在区间\([k\times 2,n]\),直接相邻构造即可,因为相邻数字的\(gcd=1\),不会影响答案。
至此,本题得解,代码如下:
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int T;
int main()
{
cin>>T;
while(T--)
{
int n,k;
scanf("%d%d",&n,&k);
if(k > n/2)
{
cout<<"No"<<endl;
continue;
}
cout<<"Yes"<<endl;
cout<<"1 ";
for(int i=n;i>=2*k+1;i--) cout<<i<<" "; //多余部分直接输出
for(int i=2;i<=2*k;i*=2) cout<<i<<" "; //构造2的整次幂
for(int i=3;i<=2*k;i+=2) //奇数构造
{
for(int j=i;j<=2*k;j*=2) cout<<j<<" ";
}
cout<<endl;
}
return 0;
}
本文作者:SXqwq,转载请注明原文链接:https://www.cnblogs.com/SXqwq/p/17636388.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!