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
  • 相关阅读:
    UVA12125 March of the Penguins (最大流+拆点)
    UVA 1317 Concert Hall Scheduling(最小费用最大流)
    UVA10249 The Grand Dinner(最大流)
    UVA1349 Optimal Bus Route Design(KM最佳完美匹配)
    UVA1212 Duopoly(最大流最小割)
    UVA1395 Slim Span(kruskal)
    UVA1045 The Great Wall Game(二分图最佳匹配)
    UVA12168 Cat vs. Dog( 二分图最大独立集)
    hdu3488Tour(KM最佳完美匹配)
    UVA1345 Jamie's Contact Groups(最大流+二分)
  • 原文地址:https://www.cnblogs.com/to-the-end/p/9923052.html
Copyright © 2011-2022 走看看