【NOIP2018复习】阶乘(数论)

1174.阶乘

时间限制:1000MS内存限制:256000KB

题目描述

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

输入

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

输出

共一行
一个正整数m。

输入样例复制

1
6

输出样例复制

3

说明

样例解释: 当p=6,q=1时,p*q=3! Data Constraint 对于10%的数据,n<=10 对于30%的数据,n<=1000 对于100%的数据,n<=100000,a[i]<=100000

 

 题解:可以把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相乘,二分判断即可。

var

  m,pm,num,l,r,ans,i,n,j:longint;

  a,t,b,p:array[0..10000000]of longint;

  f:array[0..10000000]of boolean;

procedure sushu(x:longint);

var

  i,j:longint;

begin

  i:=1;

  f[0]:=false;

  f[1]:=false;

  for i:=2 to x do

    begin

      if f[i]=true

        then begin

               inc(num);

               p[num]:=i;

               b[i]:=i;

             end;

      for j:=1 to num do

        begin

          f[p[j]*i]:=false;

          b[p[j]*i]:=b[i];

          if i mod p[j]=0 then break;

          if i*p[j+1]>x then break;

        end;

    end;

end;

procedure add(x:longint);

begin

  while x>1 do

    begin

      if(b[x]>pm) then pm:=b[x];

      inc(t[b[x]]);

      //writeln(b[x]);

      x:=x div b[x];

    end;

end;

function check(x:longint):boolean;

var

  i:longint;

  j,s:int64;

begin

  for i:=1 to pm do

    begin

      if f[i]=false then continue;

      j:=i;

      s:=0;

      while(j<=x) do

        begin

          s:=s+(x div j);

          j:=j*i;

          if s>=t[i] then break;

        end;

      if s<t[i] then exit(false);

    end;

  exit(true);

end;

procedure init;

begin

  for i:=1 to n do

    begin

      read(a[i]);

      add(a[i]);

    end;

end;

begin

  //assign(input,'1.in');reset(input);

  readln(n);

  fillchar(f,sizeof(f),true);

  sushu(1000000);

  init;

  l:=pm;r:=1000000000;

  while(l<r) do

    begin

      m:=(l+r)div 2;

      if check(m) then r:=m

        else l:=m+1;

    end;

  writeln(l);

  //close(input);

end.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值