数论cf300E

来源:互联网 发布:淘宝爆款推广计划 编辑:程序博客网 时间:2024/06/05 20:48

题意:给定N个数a1,a2,a3...aN,现在要求最小的n满足 n!/(a1!*a2!*...*aN!) 是一个正整数的最小的n。

分析:这题的想法很明确,就是分解a1!*a2!*...*aN!,把其分解成质因子相乘的形式,这个都很熟悉了,然后就是对每一个质因子二分搜索出一个数字下界,最后求其中最大的一个数,问题的关键就是如何分解这样一个表达式成一个质因子相乘的形式。使用一个cnt数组来表示每一个数的在乘积中出现的次数,然后从后往前假设一个数出现了k次,那么如果这个数是素数则不用更新,如果一个数是合数则将其分解成两部分,一个是该数最小的质因子,一个是除以这个质因子之后的值,接着一直做下去,就能够把所有的素因子全部统计起来,最后再对每一个素因子都二分搜索。

typedef long long LL ;const int maxn  = 10000000 ;int minfactor[maxn + 10] ;vector<int> prime ;LL cnt[maxn + 10] ;void getprime(){     int i , j ;     memset(minfactor , 0 , sizeof(minfactor)) ;     prime.clear()  ;     for(i = 2 ; i <= maxn ; i++){           if(!minfactor[i]){                 minfactor[i] = i ;                 prime.push_back(i) ;           }           for(j = 0 ; j < prime.size() && prime[j]*i <= maxn ; j++){                 minfactor[i*prime[j]] = prime[j] ;                 if(i % prime[j] == 0) break ;           }     }}LL  sum ;LL  gao(int x){     LL L = 1 ,  R = sum  , ans  , M , s , m ;     while(L <= R){          m = M = (L + R) >> 1 ;          s = 0 ;          while(m) s += (m/=x) ;          if(s >= cnt[x]){ ans = M ; R = M-1 ;}          else L = M+1 ;     }     return ans ;}int  main(){     getprime() ;     int n , i , x , m ;     LL  ans ;     while(cin>>n){          m = sum = 0 ;          memset(cnt , 0 , sizeof(cnt)) ;          for(i = 1 ; i <= n ; i++){                scanf("%d" ,&x) ;                sum += (LL)x ;                cnt[x]++  ;                m = max(m , x) ;          }          for(i = m-1 ; i>=2 ; i--)  cnt[i] += cnt[i+1] ;          for(i = m ; i >= 2 ; i--){                if(minfactor[i] != i){                        cnt[minfactor[i]] += cnt[i] ;                        cnt[i/minfactor[i]] += cnt[i] ;                }          }          ans = 1 ;          for(i = 0 ; i < prime.size() && prime[i] <= m ; i++){                ans = max(ans , gao(prime[i])) ;          }          cout<<ans<<endl ;      }      return 0 ;}



0 0
原创粉丝点击