NOIP复习模拟赛day5

前言 

今天的题目真TM的♂......

题目

1.小半

(half.pas/c/cpp)

【问题描述】

“释然、慵懒、尽欢,

时间风干后你与我再无关,

没答案,怎么办,看不惯自我欺瞒。

灯火阑珊,释然的少年写下了n个正整数,它们的乘积为p。

月色旖旎,少年忽然想到,如果把p再乘上一个正整数q能让它们的积为某个数的阶乘,则称这个数的阶乘为完美阶乘,这个数则为完美数,他厌倦了那些纷扰,只想要知道完美数的最小值,希望你能告诉他。

“灯火阑珊,

我的心借了你的光是明是暗。——《小半》

【输入】

共两行。

第一行一个正整数n

第二行n个正整数a[i],代表少年写下的n数。

【输出】

共一行

一个正整数,代表完美数的最小值。

【输入输出样例】

1

6

3

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

【数据范围】

对于10%的数据,n<=10

对于30%的数据,n<=1000

对于100%的数据,n<=100000,a[i]<=100000

官方题解:

10%~30%:各种暴力
100%:题目要求一个最小的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个
所以27!里面有13个3相乘。
用这个方法就可以求得m!有多少个ai相乘,二分判断即可。

这是一道水题,相信大家都切了o(* ̄︶ ̄*)o

官方标程:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #define fo(i,a,b) for(int i=a;i<=b;i++)
 6 #define fd(i,a,b) for(int i=a;i>=b;i--)
 7 #define maxn 100005
 8 #define ll long long
 9 using namespace std;
10 
11 int bz[maxn],pri[maxn],fr[maxn];
12 
13 int cnt[maxn];
14 
15 int a[maxn][2],tot;
16 
17 int n;
18 
19 void pre(){
20     fo(i,2,100000) {
21         if (bz[i]==0) pri[++pri[0]]=i,fr[i]=i;
22         fo(j,1,pri[0]) {
23             if (i * pri[j]>100000) break;
24             bz[i*pri[j]]=1;
25             fr[i*pri[j]]=pri[j];
26             if (i % pri[j]==0) break;
27         }
28     }
29 }
30 
31 void pred(){
32     int x;
33     scanf("%d",&x);
34     while (x!=1) {
35         cnt[fr[x]]++;
36         x=x / fr[x];
37     }
38 }
39 
40 ll count(ll x,ll y){
41     ll ret=0;
42     while (x>=y) {
43         ret=ret+x / y;
44         x=x / y;
45     }
46     return ret;
47 }
48 
49 bool check(ll x) {
50     fo(i,1,tot) if (count(x,a[i][0])<a[i][1]) return 0;
51     return 1;
52 }
53 
54 int main(){
55     pre();
56     scanf("%d",&n);
57     fo(i,1,n) pred();
58     fo(i,1,100000) if (cnt[i]) {
59         ++tot;
60         a[tot][0]=i;
61         a[tot][1]=cnt[i];
62     }
63     if (tot==0) {
64         cout<<1;
65         return 0;
66     }
67     ll ans=0,l=2,r=(ll)1e10;
68     while (l<=r) {
69         ll mid=(l+r) / 2;
70         if (check(mid)) {
71             r=mid-1;
72             ans=mid;
73         }
74         else l=mid+1;
75     }
76     cout<<ans;
77     return 0;
78 }
View Code

自己bb的题解:  

  首先,这一题是真的♂,我打了一个早上,才推出了一半。(我还是太菜了)(才发现陈徽桓是个大佬,如果大家想要了解更多资讯,请手动百度陈徽桓;)

猜你喜欢

转载自www.cnblogs.com/to-the-end/p/9923052.html