题意:
给出一个数n,n是int范围,找出满足 n = x^b ,b的最大值。x为整数。
分析:
先打个素数表,再将n进行素因子分解,在对它的素因子的指数进行取最大公因数,例如 4500 = 2 ^ 2 * 3 ^ 2 * 5 ^ 4, 取gcd 后 = 2 ^ 2 * 3 ^ 2 * (5^2) ^ 2 = (2 *3 * (5^2) ) ^ 2;
故这个gcd就是结果。当n是负数时,因为一个数的偶数次方一定为正数,所以x一定为奇数,所以需要将它的素因子个数全部转换为奇数再处理。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 1000010;
bool vis[MAXN];
long long prime[MAXN/10];
int tot = 0;
void getPrime()//求素数
{
for(long long i = 2; i < MAXN; i++)
if(!vis[i])
{
prime[tot++] = i;
for(long long j = i*i; j < MAXN; j += i)
vis[j] = true;
}
}
int a[1000];//保存素因子
int b[1000];//保存素因子的个数
int cnt;
void sbreak(long long n) //进行素因子分解
{
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
cnt = 0;
for(int i = 0; prime[i]*prime[i] <= n; i++)
{
if(n%prime[i] == 0)
{
a[cnt] = prime[i];
while(n%prime[i] == 0)
{
b[cnt]++;
n /= prime[i];
}
cnt++;
}
}
if(n != 1)
{
a[cnt] = n;
b[cnt++] = 1;
}
}
int gcd(int a, int b)
{
return b?gcd(b,a%b):a;
}
int main()
{
int T, ans, kase = 1, flag;
long long n;
getPrime();
scanf("%d", &T);
while(T--)
{
flag = 1;//标志,判断n是正数还是负数
scanf("%lld", &n);
if(n < 0) {n = -n, flag = 0;}
sbreak(n);
int t = b[0];
if(!flag) //如果n是奇数
{
if(t%2 == 0)
{
while(t%2 == 0) t /= 2;
}
for(int i = 0; i < cnt; i++) //将它的素因子的个数化为奇数
{
if(b[i]%2 == 0)
{
while(b[i] %2 == 0) b[i] /= 2;
}
t = gcd(t,b[i]);
}
}
else for(int i = 0; i < cnt; i++) t = gcd(t, b[i]);
printf("Case %d: %d\n", kase++, t);
}
return 0;
}