JZOJ 5791. 【NOIP2008模拟】阶乘

Description

有n个正整数a[i],设它们乘积为p,你可以给p乘上一个正整数q,使p*q刚好为正整数m的阶乘,求m的最小值。
 

Input

共两行。
第一行一个正整数n。
第二行n个正整数a[i]。

Output

共一行
一个正整数m。
 

Sample Input

1
6

Sample Output

3

样例解释:
当p=6,q=1时,p*q=3!
 
 

Data Constraint

对于10%的数据,n<=10
对于30%的数据,n<=1000
对于100%的数据,n<=100000,a[i]<=100000
 
 
做法:

题目要求一个最小的m使m!包含p这个因子。

可以把p分解质因数,假设p=∏ai^bi(ai为质数),那么只要m!包含了每个ai^bi,m!就包含p。

所以对于每个ai^bi,分别求出满足条件的最小的m,取最大值即可。

怎么求m?

先看一个简单的问题:

27!里面有多少个3相乘?

27!=1*2*...*27

包含1个3的数有27/(3^1)=9个

包含2个3的数有27/(3^2)=3个

包含3个3的数有27/(3^3)=1个

总共:9+3+1=13个

扫描二维码关注公众号,回复: 2713792 查看本文章

所以27!里面有13个3相乘。

用这个方法就可以求得m!有多少个ai相乘,二分判断即可。

代码如下:

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #define LL long long
 5 #define N 600007
 6 using namespace std;
 7 LL n, zs[N], T, a[N];
 8 LL tot = 1, ans;
 9 bool b[N]; 
10 
11 void Pre_work()
12 {
13     for (int i = 2; i <= N / 2; i++)
14     {
15         if (!b[i])
16         {
17             zs[++zs[0]] = i;
18             for (int j = 1; j <= zs[0]; j++)
19                 if (i * zs[j] > N / 2)    break;
20                 else    b[zs[j] * i] = 1;
21         }
22         else
23         {
24             for (int j = 1; j <= zs[0]; j++)
25                 if (i * zs[j] > N / 2)    break;
26                 else    b[zs[j] * i] = 1;
27         }
28     }
29 }
30 
31 LL max(LL a, LL b)
32 {
33     return a > b ? a : b;
34 }
35 
36 void Cl(LL x)
37 {
38     for (int i = 1, p = x; p > 1; i++)
39         for (; p % zs[i] == 0; p /= zs[i])
40         {
41             if (!b[p])
42             {
43                 a[p]++;
44                 T = max(T, p);
45                 p = 1;
46                 break;
47             }
48             a[zs[i]]++, T = max(T, zs[i]);
49         }
50 }
51 
52 bool Check(LL ain)
53 {
54     for (int i = 1; i <= T; i++)
55     {
56         int j = zs[i];
57         LL Jl = 0;
58         for (LL k = j; (k <= ain) && (Jl < a[zs[i]]); k *= j) Jl += ain / k;
59         if (Jl < a[zs[i]])    return 0;
60     }
61     return 1;
62 }
63 
64 void Find()
65 {
66     LL l = 1, r = 100000000;
67     while (l < r)
68     {
69         LL mid = (l + r) / 2;
70         if (Check(mid))    r = mid;
71         else l = mid + 1;
72     }
73     printf("%lld", l);
74 }
75 
76 int main()
77 {
78     freopen("factorial.in", "r", stdin);
79     freopen("factorial.out", "w", stdout);
80     scanf("%lld", &n);
81     LL x;
82     Pre_work();
83     for (int i = 1; i <= n; i++)
84     {
85         scanf("%lld", &x);
86         if (!b[x])
87         {
88             a[x]++, T = max(T, x);
89             continue;
90         } 
91         Cl(x);
92     }
93     Find();
94 }
View Code

猜你喜欢

转载自www.cnblogs.com/traveller-ly/p/9461939.html