zcmu--5123分糖果---lcm

题目链接https://acm.zcmu.edu.cn/JudgeOnline/problem.php?id=5123

Description
旧的一年过去,小明的生日(1月11号,小光棍节)又快到了,作为母胎单身的他打算脱单,于是他便准备开一个party来暗中相亲(想想都知道不可能成功的)。他为了能吸引到更多的女生,于是事先准备了好多糖果,准备派发给来party的每个人。可是一个难题摆在了他面前,他现在还无法确定到时候究竟会有多少人来,于是他为了糖果能被平分,就先去调查了一下能到场人数的可能性。

他收集到了nn种可能,现在他需要你的帮助,帮他看看他到底需要准备多少糖果,可以使得最后的糖果都被平分而没有剩余。
Input
第一行只有一个数字T,代表了有T组测试。

每组测试的第一行只有一个数n,代表了有n种可能。

第二行有n个数字ai,代表了其中可能来的人数。

题目保证所有的输入数据以及答案在int的范围之内,n≥1。

Output
对于每组测试,输出小明最少需要准备的糖果数。

Sample Input
1
2
6 15
Sample Output
30
HINT

lcm(a, b) = a * b / gcd(a, b)

前言,前几天学了一个筛子,然后直接干掉这道题,但是今天回来看我的代码,尽然有点吃力,哎,脑子记性不好,所以今天给写下来,便于回溯。其实吧,这题可以当一个模板,感觉很实用。
思路,暴力??这题没有给数据,但是很明显暴力大概率超时(我没试过,会筛谁还暴力)。
第一步、我们需要打印一个素数表,也就是存放素数的数组,我的朋友们写过很多厉害的素数表讲解,可以参考https://blog.csdn.net/qq_52480906/article/details/114011325
我用的算是一个线性筛(有可能不是)
筛法函数如下:

void getp()
{
    int vis[1000],cnt = 0;
    memset(vis,0,sizeof(vis));
    for(int i = 2;i<1000;i++)
    {
        if(vis[i]==0)  //这个数没有被其他数筛掉,是素数.
        {
            vis[i] = i;
            prime[++cnt] = i;
        }
        for(int j = 1;j<=cnt;j++)
        {
            if( vis[i] < prime[j]||i*prime[j]>1000) break;	//
            vis[i*prime[j]] = prime[j];
        }
    }
}

第二步、因为每一个数都可以拆解成若干素数相乘,比如8 = 2 * 2 *2,
10 = 2 * 5,等等,都可以进行拆解。再由数学知识,我们的lcm就等于所有质数的最大值,也就是每个数所分解后,取每个质数最大的次方,比如6和8,我们分解后得到如下结果
在这里插入图片描述
而我们的结果就是2 * 2 * 2 * 3 = 24。(2的最大为8提供的3次方)。
因此我们第二步就是将每个数分解,并将每一个质数所算出来的次方储存到另一个数组里。
第三步 对最后的数组做乘法即可。
AC代码

#include<bits/stdc++.h>
using namespace std;
int pri[1000];
 
void getp()
{
    int vis[1000];
    int m = 0;
    memset(vis,0,sizeof vis);
    for(int i = 2;i<1000;i++)
    {
 
        if(vis[i]==0)
        {
            vis[i] = i;
            pri[++m] = i;
        }
        for(int j = 1;j<=m;j++)
        {
            if(pri[j] > vis[i] ||i*pri[j]>=1000) break;
            vis[pri[j]*i] = pri[j];
        }
    }
 
}
int main()
{
    getp();
    int t;
    cin>>t;
    while(t--)
    {
        int p[1000];
        memset(p,0,sizeof p);
        int n;
        cin>>n;
        int sum1=1;
        int mx_x=0;
        for(int i = 1;i<=n;i++)
        {
            int x;
            cin>>x;
            mx_x = max(mx_x,x);	//找出最大的数,缩小最后相乘的质数范围
            int cnt = 0;
            for(int j = 1;x!=1;j++)		//第二步,分解每一个数,p[j]可以理解成我在pri数组下面又开了一个数组,二维可能好理解,都一样。
            {
                cnt = 0;
                while(x%pri[j]==0) cnt++,x/=pri[j];
                p[j] = max(p[j],cnt);
            }
        }
        for(int i = 1;pri[i]<=mx_x;i++)	//直接相乘即可.
            while(p[i]!=0) sum1*=pri[i],p[i]--;
        cout<<sum1<<endl;
    }
 
}

**总结:**其实用这个方法也可以算gcd,只要找到每个数被分解成那些质数,然后不用处理次方,直接加到p数组里,最后知道将p数组里数据等于n(要算gcd的数据总数)的,所对应的素数相乘即可。

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

手撕键盘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值