【数学】codeforces C. Maximal GCD
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.
然后接下来考虑怎么使最大公约数最大:
因为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了,所以要写成
1 if(sum[m]<=n/d[i]) 2 { 3 return true; 4 } 5 return false;
2. 对于i*i==n的要特别判断
3. 要特别考虑1 1的corner case.
【Accepted】
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 }