zoukankan      html  css  js  c++  java
  • 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的题解:  

      首先,这一题是真的♂,我打了一个早上,才推出了一半。(我还是太菜了

      这题首先我们要打一个欧拉筛,来筛出1~100000内的质数;

      然后我们要把每个A分解质因数;

      然后二分1~100000的完美数,找出这个阶乘里所含的质因子的个数,与我们分解的A的质因数进行比较,如果大于等于A的质因数就继续往左区间寻找答案,否则反之...

      如何寻找m!分解后n因子的个数???

      给定两个数m,n

      求m!分解质因数后因子n的个数。

      这道题涉及到了大数问题,如果相乘直接求的话会超出数据类型的范围。

      下面给出一种效率比较高的算法,我们一步一步来。

      m!=1*2*3*……*(m-2)*(m-1)*m

      可以表示成所有和n倍数有关的乘积再乘以其他和n没有关系的

          =(n*2n*3n*......*kn)*ohter     other是不含n因子的数的乘积   因为 kn<=m 而k肯定是最大值  所以k=m/n

          =n^k*(1*2*......*k)*other  

          =n^k*k!*other     

      从这个表达式中可以提取出k个n,然后按照相同的方法循环下去可以求出k!中因子n的个数。

      每次求出n的个数的和就是m!中因子n的总个数。

     1 #include<stdio.h>  
     2 int main()  
     3 {  
     4     int t;  
     5     scanf("%d",&t);  
     6     while(t--)  
     7     {  
     8         int m,n;  
     9         scanf("%d%d",&m,&n);  
    10         long int sum=0;  
    11         while(1)  
    12         {  
    13             sum+=m/n;  
    14             m=m/n;  
    15             if(m==0)  
    16                 break;  
    17         }  
    18         printf("%d
    ",sum);  
    19     }  
    20 }  
    View Code

    代码...(推了一个下午)   

     1 //NOIPRP++
     2 #include<bits/stdc++.h>
     3 #define Re register int
     4 using namespace std;
     5 int N,A,MinPrime[100005],Prime_Num[100005],Num[100005];
     6 long long l=1,r=1e10,ans;
     7 bool Isprime[100005];
     8 inline void read(int &x){
     9     x=0; char c=getchar(); bool p=1;
    10     for (;'0'>c||c>'9';c=getchar()) if (c=='-') p=0;
    11     for (;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    12     p?:x=-x;
    13 }
    14 inline void Check_Prime(){
    15     memset(Isprime,true,sizeof(Isprime));
    16     for (Re i=2;i<=100000;i++){
    17         if (Isprime[i]) Prime_Num[++Prime_Num[0]]=MinPrime[i]=i;
    18         for (Re j=1;j<=Prime_Num[0]&&i*Prime_Num[j]<=100000;j++){
    19             Isprime[i*Prime_Num[j]]=false;
    20             MinPrime[i*Prime_Num[j]]=Prime_Num[j];
    21             if (i%Prime_Num[j]==0) break;
    22         }
    23     }
    24 }
    25 inline bool Check(long long K){
    26     for (Re i=1;i<=Prime_Num[0];i++){
    27         long long Tmp=K,Val=0;
    28         while (Tmp){Val+=Tmp/Prime_Num[i];Tmp/=Prime_Num[i];}
    29         if (Val<Num[Prime_Num[i]]) return false;
    30     } 
    31     return true;
    32 }
    33 int main(){
    34     Re i,j; 
    35     Check_Prime();
    36     read(N);
    37     for (i=1;i<=N;i++){
    38         read(A);
    39         while (A^1){++Num[MinPrime[A]];A/=MinPrime[A];}
    40     }
    41     while (l<=r){
    42         long long Mid=(l+r)>>1;
    43         if (Check(Mid)) ans=Mid,r=Mid-1;
    44         else l=Mid+1;
    45     }
    46     printf("%lld",ans);    
    47     return 0;
    48 }
    49 //NOIPRP++
    View Code
  • 相关阅读:
    Object doesn't support property or method 'flat'
    yapi的部署
    mongoDB 安装
    排序
    直播原理
    文件怎么都删不掉,压缩,命令行都不行
    computed和watch
    docker安装
    跨域问题的解决方案
    一次普通的http请求
  • 原文地址:https://www.cnblogs.com/to-the-end/p/9923052.html
Copyright © 2011-2022 走看看