1. 程式人生 > >【NOIP2018複習】階乘(數論)

【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.