洛谷P1414 又是毕业季II 数论

洛谷P1414 又是毕业季II
数论

d[ i ] 表示这些数中有几个数有因数 i
对于输入的每个数 都sqrt(val) 记录下
然后问你 n个数的最大公约数是多少,
相当于是问你 有 n 个数 有相同因数 ,这样最大的因数是多少

《又是毕业季II》解题报告

By lzn 数论常规题。

一开始很容易想到枚举n个数取k个的所有组合,然后分别用辗转相除法求最大公约数,但是复杂度明显不符合要求,于是必须换一种思路。

我们想到,k个数的公约数含义就是这k个数均含有某个因数,如果我们把所有数的因数全部求出来,发现有k个数均含有某个因数,那么这个数必然是这k个数的公约数。其中找出最大的就是它们的最大公约数。但是要如何高效的做到这点呢?考虑到对于k=1,2……,n都要求出,我们可以这么做:

1、 求出每个因数出现的次数。

2、 对于每个次数记录最大的因数。

3、 根据f[k]=max(f[k],f[k+1])逆向递推。(如果已经知道k个数的最大公约数是m,那么l(l<k)个数的最大公约数一定大于等于m)。
具体为什么这么做,留给大家自己思考啦~~

算法复杂度o(n*sqrt(inf))。

 1 #include <cstdio>
 2 #include <cmath>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <string>
 6 #include <algorithm>
 7 #include <iostream>
 8 #include <iomanip>
 9 using namespace std ; 
10 
11 const int maxn = 10011,inf = 1e6+11 ; 
12 int n,mx,x,y ; 
13 int d[inf] ; 
14 
15 inline int read() 
16 {
17     char ch = getchar() ; 
18     int x = 0,f = 1 ; 
19     while(ch<'0'||ch>'9') { if(ch=='-') f = -1 ; ch = getchar() ; } 
20     while(ch>='0'&&ch<='9') { x = x*10 + ch-48 ; ch = getchar() ; } 
21     return x*f ; 
22 }
23 
24 int main() 
25 {
26     n = read() ; 
27     for(int i=1;i<=n;i++) 
28     {
29         x = read() ; 
30         mx = max(mx,x) ; 
31         y = int(sqrt( x )+0.0001) ; 
32         for(int j=1;j<=y;j++) 
33             if(x%j==0) 
34             {
35                 d[ j ]++ ; 
36                 if(j*j!=x) d[ x/j ]++ ; 
37             }
38     }
39     for(int i=1;i<=n;i++) 
40     {
41         while(d[mx] < i ) mx-- ; 
42         printf("%d
",mx) ; 
43     }
44     return 0 ; 
45 }
原文地址:https://www.cnblogs.com/third2333/p/7083537.html