题目
将 $n$($1 < n leq 10^{18}$)质因数分解,求质因数幂的最小值。
分析
直接质因数分解,不太行。
可以这样想,对小区间质因数分解,n变小了,再枚举答案。
打印1-10000之间的素数表然后质因数分解,分解完剩下的那个数,
- 两种质数(肯定大于 $10^4$)相乘,最多二次,合起来也是一个平方数;
- 三种或以上质数相乘,只可能为一次,不用考虑。
- 一种质数,最多为四次方,枚举四、三、二次方,如果都不是,就是单个质数
要注意:先看是4次方再看2次方(因为如果满足4次方一定满足2次方,但是满足4次方也满足2次方,2次方的话就不是质因数了),3次方无所谓,因为开3次方会损失精度,所以就二分一下。
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll n; //返回n以内素数的个数 //埃氏筛法O(nloglogn) const int maxn = 100000 + 10; int prime[maxn]; //prime[i]表示第i个素数 bool is_prime[maxn + 1]; //is_prime[i]为true表示i是素数 int sieve(int n) { int cnt = 0; for (int i = 0; i <= n; i++) is_prime[i] = true; is_prime[0] = is_prime[1] = false; for (int i = 2; i <= n; i++) { if (is_prime[i]) { prime[cnt++] = i; for (int j = i * i; j <= n; j += i) is_prime[j] = false; //i * i可能爆int } } return cnt; } bool is_three(ll n) //是否能开立方 { ll l = 10000, r = 1e6; while(l <= r) { ll mid = (l+r) >> 1; ll tmp = mid*mid*mid; if(tmp == n) return true; else if(tmp > n) r = mid-1; else l = mid+1; } return false; } int main() { int cnt = sieve(10000); //筛出10000内的质数 int T; scanf("%d", &T); while(T--) { scanf("%lld", &n); int ans = 100; for(int i = 0;i < cnt;i++) { if(n % prime[i] == 0) { int tmp = 0; while(n % prime[i] == 0) { n /= prime[i]; tmp++; } ans = min(tmp, ans); } if(n == 1) break; } if(ans == 1){ printf("1 "); continue;} if(n == 1){ printf("%d ", ans); continue;} ll t1 = (ll)sqrt(n); ll t2 = (ll)sqrt(t1); if(t2*t2*t2*t2 == n) ans = min(ans, 4); else if(t1*t1 == n) ans = min(ans, 2); else if(is_three(n)) ans = min(ans , 3); else ans = min(ans, 1); printf("%d ", ans); } return 0; }