Maximal GCD CodeForces

  题意:给n和k,要求构造一个长度为k的序列,要求这个长度为k的序列之和为n,且这k个数的gcd取到max。假设gcd为m,则m*(a1+a2+a3+....+ak)=n(由此可以知道m也是n的约数),题目要求序列递增,所以序列a1=1,a2=2,a3=3....a(k-1)=k-1,ak的话就需要特殊处理一下,因为要m尽可能大,所以ak尽可能要小,优先取1,实在不行也可以往上加。但是这样求ak很麻烦,我们可以找到了满足条件的n的最大的m的时候,可以先把前k-1项序列都打印出来,并求得和sum,(n-sum)=m*ak就是剩下的那项了。接下来讲讲如何求满足条件的最大的m,我们可以遍历一遍n的全部约数,对每个约数v判断是否v*(1+2+3+4+5+...+k)>n,1.如果满足的话,说明ak取到k(等同于序列的第k项)也就是最小了,即这个序列和都最小了,还是大于n,说明这个v太大了,所以这个v不取。2.如果v*(1+2+3+4+5+...+k)<=n,说明这个v是可取的,当等号成立时这个ak取到k(等同于序列的第k项)也就是取到了最小,最后输出这个序列的时候输出第k项的时候,输出的是v*k,当小于号成立时,最后输出这个序列的时候输出第k项的时候,输出的是v*p(2<=p);最后还要注意一下这题long long 都会爆,主要是在求v*(1+2+3+4+5+...+k)=v*(1+k)*k/2的时候容易爆,这个时候就需要处理,1.可以先把v以过去除以n,2.在输入了n和k的时候判断一下,如果k>=1e6的话那么(1+k)*k>=1e12了,而n最大才1e10,所以v*(1+2+3+4+5+...+k)<=n这个条件是肯定不满足的,不管v取什么,所以这种情况这个序列是构造不出来的。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main()
{
    std::ios::sync_with_stdio(false);
    ll n,k,ans=-1;
    int flag=0;
    cin>>n>>k;
    if(k>=1000000) {cout<<-1<<endl;return 0;}
    for(ll i=sqrt(n);i>=1;i--)
    {
        if(n%i!=0)
            continue;
        ll yz[3]={0,n/i,i};
        for(int j=1;j<=2;j++)
        {
            if((k*(1+k)/2)>n/yz[j])
                continue;
            if((k*(1+k)/2)<=n/yz[j])
            {
                ans=max(ans,yz[j]);
                flag=1;
            }


        }


    }
    if(!flag) {cout<<-1<<endl;return 0;}
    ll tmp=0,sum=0;
    for( ll j=1;j<=k-1;j++)
    {
        tmp=j*ans;
        sum+=tmp;
        cout<<tmp<<" ";

    }
    cout<<n-sum<<endl;
    return 0;

}
原文地址:https://www.cnblogs.com/eason9906/p/11754931.html