LightOj 1024 - Eid (求n个数的最小公约数+高精度)

时间:2023-03-31 09:10:44

题目链接:http://lightoj.com/volume_showproblem.php?problem=1024

题意:给你n(2<=n<=1000)个数, 然后求n个数的最小公倍数,每个数的大小是1---10000;所以答案会很大,可能达到1000个4位数相乘;所以结果很大,将近4000位;

所以一定会涉及到高精度运算;同时我们也不能直接循环求最小公倍数;我们可以把一个数分解成多个质数相乘,然后找到所有数中,出现的质数最多的那个对应的次方,然后再把结果乘起来即可;

例如样例

4

5 6 30 60

5 : 5 //说明最小公倍数的因子中一定有一个5

6 : 2*3 //说明最小公倍数的因子中一定有一个2和一个3;

30 : 2*3*5 //说明最小公倍数的因子中一定有一个2和一个3和一个5;

60 : 2^2*3*5 //说明最小公倍数的因子中一定有2个2和一个3和一个5;

所以我们可以忽略那些个数比较少的, 找到说明结果中一定含有 2个2 1个3 1个5;

需要注意的是,因为每次进行大整数相乘时都是用的N,以至于TLE了无数次,所以可以用多位一起输出的方法进行;

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
typedef long long LL;
#define N 10001
using namespace std;
const double eps = 1e-; int f[], p[], k = ; void Prime()
{
for(int i=; i<; i++)
{
if(!f[i])p[k++] = i;
for(int j=i; j<; j+=i)
f[j] = ;
}
} int ans[], cnt[N]; void Mul(int a[], int num)
{
for(int i=; i<; i++)
a[i] = a[i]*num;
for(int i=; i<; i++)
{
a[i+] += a[i]/;
a[i] = a[i]%;
}
} void PUTS(int a[])
{
int i=;
while(i>= && a[i]==) i--;
printf("%d", a[i--]);
while(i>=) printf("%04d", a[i--]);
printf("\n");
} int main()
{
Prime();
int n, T, t = ;
scanf("%d", &T);
while(T--)
{
memset(cnt, , sizeof(cnt));
memset(ans, , sizeof(ans)); int num;
scanf("%d", &n);
for(int i=; i<=n; i++)
{
scanf("%d", &num);
for(int j=; j<k && p[j]*p[j] <= num; j++)
{
int s = ;
while(num%p[j] == )
{
s ++;
num /= p[j];
}
cnt[p[j]] = max(cnt[p[j]], s);
}
if(num > )
cnt[num] = max(cnt[num], );
}
ans[] = ;
for(int i=; i<N; i++)
{
if(!cnt[i]) continue;
int ret = ;
for(int j=; j<cnt[i]; j++)
ret *= i;
Mul(ans, ret);
}
printf("Case %d: ", t++);
PUTS(ans);
}
return ;
}