Number Factorization

文章讨论了一种解决寻找能组成给定数字n的所有质因数之和最大的算法。通过构建sum数组,利用质因数分解,确保大因数尽可能大,小因数尽可能小,从而得出最大和。代码实现中,使用了双端队列存储质因数及其出现次数,并计算了因数的乘积和加和。
摘要由CSDN通过智能技术生成

一,题目

二,思路

(思路基本就一本正经的胡说八道,当时只是举了几个例子,凭着直觉乱写一通,然后莫名其妙的过了)

(1)首先不要管数组p和a,我们可以用一个sum数组,而sum数组每一个数乘起来等于n,而sum数组每一个数组的加和就是我们想要的答案。这时,数组a,p和sum的关系就是,sum中p个相同的数的乘积在数组a中表示为a^p(即a中p个相同的数乘在一起),而sum中多个相同数的加和在数组a中表示为a*p(即a中p个相同的数加在一起)。

说白了,sum中每个数的乘积就是题目中下面的东西

而sum每个数的加和就是题目中的下面的东西

所以题目要我们求的即组成n的因数(这里指乘在一起刚好组成n的所有因数,包括相同的质因数)的和最大是多少,而且这些数中自个的因数必须是质数。

(2)那怎么求出自个的因数是质数的数呢?首先我们先求出n中所有质因数,那么自个的因数是质数的数肯定是这些数的乘积(当然,每个值相同的数只能乘一次)或本身,比如100质因数为2,2,5, 5,那么自个的因数是质数的因数可以是2,2,5,5,10,10,其中2,5是这些数的本身,10是这些数的乘积,好了,求出自个的因数是质数的数的问题解决了。

(3)那怎么求的即组成n的因数(这里指乘在一起刚好组成n的所有因数)的最大和,(开始胡说八道了)首先,根据基本不等式,a*b如果是个定值的话,当a=b时,a+b最小,而a或b越大,说明a+b越大。这时,我们可以将这个性质用于这题(虽然不知道对不对),即组成n的因数(这里指乘在一起刚好组成n的所有因数)中大的因数尽可能大,小的尽可能小。那怎么办呢?我们先求出组成n的因数(这里指乘在一起刚好组成n的所有因数,包括相同的质因数),让尽可能多的质因数乘在一起组成数组sum的每一个数,比如864质因数2,2,2,3,3,3,2,2,然后用数组存起来,第一个数组sum里的数是6,第二个是6,第三个是6,第四个是2,第五个是2。这样保证了大的因数尽可能大,小自然会尽可能小,最后将他们加在一起就是所要求的答案了。

(4)当然,我的代码中的求因数和思路有点不同:即sum[i]等于第i个出现在装质因数的数组的所有元素的加和,然后因为直接输出加和,我就用ans直接把所有sum加起来,直接输出答案。而d数组储存了每个质因数a和它的个数p,只要i不大于它的个数,sum就会乘以这个质因数。而MAX用来找出i能够达到的最大值。

#include<deque>
#include<cmath>
#include<iostream>
using namespace std;
#define int long long
struct prime
{
    int a,p;
    prime(int x,int y):a(x),p(y){};
};
signed main(){
    int t;
    cin>>t;
    while(t--)
    {
        int num,a=0,p=0,MAX=0, sum=1;
        cin>>num;
        if(num==1) //如果num是1的话,这个思路的答案是错误的,所以要特判
        {
            cout<<1<<endl;
            continue;
        }
        deque<prime> d;
        for(int i=2;i*i<=num;++i)
        {
            while(num%i==0) num/=i,a=i,++p;
            if(p!=0) d.push_back(prime(a,p));
            if(d.size()!=0)MAX=max(d.back().p,MAX);
            p=0;        
        }
        if(num>1) d.push_back(prime(num,1)),MAX=max(MAX,1ll);
        int ans=0;
        for(int i=1;i<=MAX;++i)
        {
            for(int j=0;j<d.size();++j)
                if(d[j].p>=i) sum*=d[j].a;               
            ans+=sum,sum=1;
        }
        cout<<ans<<endl;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值