【数学】codeforces C. Maximal GCD

时间:2021-05-24 05:15:13

http://codeforces.com/contest/803/problem/C

【题意】

给定两个数n,k(1 ≤ n, k ≤ 10^10)

要你输出k个数,满足以下条件:

①这k个数之和等于n

②严格递增

②输出的这k个数的最大公约数q尽可能大。

【思路】

因为是严格递增,所以sum[k]>=k(k+1)/2,而n<=1e10,所以k应该在1e5多一点。

可以找出最大的满足n<=1e10的k,给定的k超出这个直接输出-1.

然后接下来考虑怎么使最大公约数最大:

【数学】codeforces C. Maximal GCD

因为q肯定也是n的约数,所以可以先把n的公约数都找出来,时间复杂度是O(sqrt(n)),从大到小排序后一次判断能不能满足q*(1+2+···+k)<=n就可以了。

【注意】

1. 判断q*(1+2+···+k)<=n不能写if(q*sum[k]<=n)

会爆的,最大的q就是n本身,当n=1e10,k=1e5的时候,q*sum[k]就爆long long了,所以要写成

【数学】codeforces C. Maximal GCD【数学】codeforces C. Maximal GCD
1 if(sum[m]<=n/d[i])
2     {
3         return true;
4     }
5     return false;
View Code

2. 对于i*i==n的要特别判断

3. 要特别考虑1 1的corner case.

【Accepted】

【数学】codeforces C. Maximal GCD【数学】codeforces C. Maximal GCD
  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <cmath>
  4 #include <vector>
  5 #include <algorithm>
  6 #include <set>
  7 #include <map>
  8 #include <queue>
  9 #include <deque>
 10 #include <stack>
 11 #include <string>
 12 #include <bitset>
 13 #include <ctime>
 14 #include<algorithm>
 15 #include<cstring>
 16 using namespace std;
 17 typedef long long ll;
 18 ll n,m;
 19 const int maxn=1e6+2;
 20 ll sum[maxn];
 21 int cou;
 22 void Init()
 23 {
 24     memset(sum,0,sizeof(sum));
 25     for(int i=1;i<maxn;i++)
 26     {
 27         sum[i]=sum[i-1]+(ll)i;
 28         if(sum[i]>=10000000000)
 29         {
 30             cou=i;
 31             break;    
 32         }
 33     }
 34 }
 35 ll d[1000000];
 36 bool cmp(ll a,ll b)
 37 {
 38     return a>b;
 39 }
 40 
 41 bool judge(int i)
 42 {
 43     if(sum[m]<=n/d[i])
 44     {
 45         return true;
 46     }
 47     return false;
 48 }
 49 void Print(int i)
 50 {
 51     for(int k=1;k<=m-1;k++)
 52     {
 53         cout<<d[i]*(ll)k<<" ";
 54     }
 55     cout<<n-d[i]*sum[m-1]<<endl; 
 56 }
 57 int main()
 58 {
 59     Init();
 60     cin>>n>>m;
 61     if(m>=cou)
 62     {
 63         printf("-1\n");
 64         return 0;
 65     }
 66     if(sum[m]>n)
 67     {
 68         printf("-1\n");
 69         return 0;
 70     }
 71     int cnt=0;
 72     ll index=0;
 73     for(int i=1;(ll)i*(ll)i<n;i++)
 74     {
 75         if(n%(ll)i==0)
 76         {
 77             d[cnt++]=(ll)i;
 78             d[cnt++]=n/(ll)i;
 79         }
 80         index=(ll)i;
 81     }
 82     index++;
 83     if(index*index==n)
 84     {
 85         d[cnt++]=index;
 86     }
 87     sort(d,d+cnt,cmp);
 88     int flag=0;
 89     for(int i=0;i<cnt;i++)
 90     {
 91         if(judge(i))
 92         {
 93             flag=1;
 94             Print(i);
 95             break;
 96         }    
 97     }
 98     if(flag==0)
 99     {
100         printf("-1\n");
101     }
102     return 0;
103 }
注意爆ll,注意corner case