数论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