洛谷 Maximal GCD

题目链接:https://www.luogu.com.cn/problem/CF803C

问题描述

请你构造一个长度为 k 的严格上升正整数序列,使得所有数的和恰好为 n,并且所有数的最大公约数最大。输出这个序列。如果没有合法的序列输出 −1。如果有多个合法的序列,可以输出任意一个。1≤n,k≤10的10次方

解题思路

①审题可得要找的序列有最大公约数最大,即他们有一个公共的能够被n整除的因数,这个因数是他们的最大公约数。【读题得】

②看k是否等于1,若为1则为自身;若大于1则进行如下操作。

③由极限思维可以知道我们可以通过初次判断n与1到k的和sum进行比较。(若小于或等于则存在这个序列,若大于则不可能存在这个序列(因为数在最初之和已经大于n了)。

④由①可以得,我们要找出1到n的关于n的所以因数,然后为了后期找最大公约数方便,要对因数进行排序。

⑤按照sum<=n/因数的条件。找到要的最大的那个因数。

⑥按照可能性先输出k-1的数,在输出n-(k-1)*因数的最后一个值。

⑦注意:时间的限制,在找因数,因数排序,找满足条件的最大因数中可以进行时间的缩短。

算法描述

#include<iostream>

#include<cmath>

using namespace std;

typedef unsigned long long ll;

void paixu(ll num[],long long j)

{

for(int i=0;i<j;i++){

ll x=i;

for(int k=i+1;k<=j;k++){

if(num[x]>num[k]) x=k;

}

if(x!=i){     //把大放在后面 ,小的放前面 

ll temp=num[i];

num[i]=num[x];

num[x]=temp;

}

}

 } 

int main()

{

ll n,k;

cin>>n>>k;

if(k==1) cout<<n<<endl;

else{

ll sum=0,i,j=0,M,num[10000];

if(k&1) sum=(k+1)/2*k;

else sum=k/2*(k+1);

if(sum>n||k>=1e6) cout<<-1<<endl;  //排除几个限制(此处不知为何不可以写成pow(10,10)

else{

for(i=1;i<=sqrt(n);i++){

if(n%i==0) {

num[j]=i;j++;

if(n/i!=i) {num[j]=n/i;j++;} 

} //也可以不用考虑因子为n本身,因为当i=n时(①k=1,此时直接输出n;②k!=1,此时n<sum,则输出-1)这两种情况上面有 

}

paixu(num,j-1);

/*for(int i=0;i<j;i++){

cout<<num[i]<<endl;

}*/

j--;

while(j>=0){

//cout<<num[j]<<endl;

if(sum<=n/num[j]) break;     //找满足条件的最大因数

j--;

}

//cout<<M<<endl;

//cout<<n-sum*num[j]+k*num[j]<<endl;

i=0;

while(i++,i<k){

cout<<num[j]*i<<' ';

}

cout<<n-(sum-k)*num[j]<<endl;

} 

}

return 0;

}

分析讨论与总结

①本题的题意理解(所有的最大公约数最大)可以知道是找他们之和的因数中满足条件的最大因数

②通过本题,知道了一些限制时间的代码写法。

③最后输出的时候可以总结的来写。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值