题目描述:
You are given positive integer number n. You should create such strictly increasing sequence of k positive numbers a1, a2, ..., ak, that their sum is equal to n and greatest common divisor is maximal.
Greatest common divisor of sequence is maximum of such numbers that every element of sequence is divisible by them.
If there is no possible sequence then output -1.
The first line consists of two numbers n and k (1 ≤ n, k ≤ 1010).
If the answer exists then output k numbers — resulting sequence. Otherwise output -1. If there are multiple answers, print any of them.
6 3
1 2 3
8 2
2 6
5 3
-1
思路:
这个题是要给一个数n,一个数k,看能不能凑出一组含k个元素的严格递增数列,这组数的和为n,还要让这组数的最大公约数最大。
刚开始,a1+a2+...+ak=n>=a1+(a1+1)+(a1+2)+...+(ak+k-1),解得1<=a1<=(n-k*(k-1)/2)/k,既然要求公约数最大,把a的所有因数找出来,从大往小一个个试,
比如,找到一个f是a1的因数,既然要f为这组数的gcd,那f一定也是n的因数,检查一下,不是就跳过,是就n/f,变成找一个严格递增数列和为n/f,就不用考虑公因数了。
刚开始把过多的注意力放到了a1上,就把所有a1可能值一个个遍历,分别找因数,分别检查,结果是错的,而且程序逻辑及其混乱+复杂,还有好多要特判的地方(疯了我已经快)因为每一个a1都有因数1,最后对于较大的a1来说(从大往小检查)总会到1就停止,以为算出了最终结果。
所以后来把所有a的所有因数放到一个set里,也方便找最大值,从大往小遍历所有因数。就好了。。。吗?
结果超时。
仔细想想,怎么办。既然最后都是a1的因数f如果满足题目条件,那么它也是n的因数,那就把n的因数找出来就好了啊。
(٩(๑>◡<๑)۶),注意的是在枚举n的因数是不要忘了f要满足a1的上下界的限制,满足的才加到set中去。
但是但是,还要注意,一开始判断可不可能构造出这么一个数列,a1+a2+...+ak=n>=ka1+k*(k-1)/2>=k+k*(k-1)/2,以为完了?nonono,要注意题目数据范围,如果来个4*10^9这种,long long也存不下啊,那咋办,用double来存k吧...
Type | Size | 数值范围 |
无值型void | 0 byte | 无值域 |
布尔型bool | 1 byte | true false |
有符号短整型short [int] /signed short [int] | 2 byte | -32768~32767 |
无符号短整型unsigned short [int] | 2 byte | 0~65535 |
有符号整型int /signed [int] | 4 byte | -2147483648~2147483647 |
无符号整型unsigned [int] | 4 byte | 0~4294967295 |
有符号长整型long [int]/signed long [int] | 4 byte | -2147483648~2147483647 |
无符号长整型unsigned long [int] | 4 byte | 0~4294967295 |
long long | 8 byte | 0~18446744073709552000 |
有符号字符型char/signed char | 1 byte | -128~127 |
无符号字符型unsigned char | 1 byte | 0~255 |
宽字符型wchar_t (unsigned short.) | 2 byte | 0~65535 |
单精度浮点型float | 4 byte | -3.4E-38~3.4E+38 |
双精度浮点型double | 8 byte | 1.7E-308~1.7E+308 |
long double | 8 byte |
|
(上表来源见下面博客)
知识点:贪心,数论(一点点)
代码:
1 #include <iostream> 2 #include <cmath> 3 #include <vector> 4 #include <set> 5 #include <algorithm> 6 using namespace std; 7 long long n; 8 double k; 9 set<long long> fac; 10 vector<long long> num; 11 int main() 12 { 13 cin >> n >> k; 14 if(k+k*(k-1)/2<=n) 15 { 16 long long uper1 = (n-k*(k-1)/2)/k; 17 long long lower1 = 1; 18 //cout << uper1 << " " << lower1 << endl; 19 long long qz = 1; 20 /*for(long long a = uper1; a>=lower1; a--) 21 { 22 for(long long i = 1; i<sqrt(a)+1; i++) 23 { 24 if(a%i==0) 25 { 26 fac.insert(i); 27 fac.insert(a/i); 28 } 29 } 30 }*/ 31 for(long long i = 1;i<sqrt(n)+1;i++) 32 { 33 if(n%i==0) 34 { 35 if(i<=uper1) 36 { 37 fac.insert(i); 38 } 39 if(n/i<=uper1) 40 { 41 fac.insert(n/i); 42 } 43 } 44 } 45 /*cout << "fac " << endl; 46 for(auto ite = fac.rbegin();ite!=fac.rend();ite++) 47 { 48 cout << *ite << " "; 49 } 50 cout << endl;*/ 51 for(auto ite = fac.rbegin(); ite!=fac.rend(); ite++) 52 { 53 //cout << "ite " << *ite << endl; 54 int flag = 1; 55 num.clear(); 56 long long sum = n/(*ite)-1; 57 int shu = 1; 58 num.push_back(shu); 59 if(sum) 60 { 61 shu++; 62 while(shu<=sum&&num.size()<k-1) 63 { 64 num.push_back(shu); 65 sum -= shu; 66 shu++; 67 68 } 69 if(shu<=sum) 70 { 71 qz = *ite; 72 //cout << "qz " << qz << endl; 73 num.push_back(sum); 74 break; 75 } 76 } 77 else 78 { 79 qz = *ite; 80 break; 81 } 82 } 83 for(int i = 0;i<num.size();i++) 84 { 85 cout << qz*num[i] << " "; 86 } 87 cout << endl; 88 } 89 else 90 { 91 cout << -1 << endl; 92 } 93 return 0; 94 }
参考资料:
年少轻狂12138,C++基本数据类型大小及表示范围,https://blog.csdn.net/weixin_40709898/article/details/79368310(间接引用,因为上面的博客也是转载但找不到原博客)