HDU_3092 Least common multiple 【dp】

题目链接

题目描述

给你第一个数n,问你把n分解成另外几个数字,求这几个数字最大的LCM(最小公倍数),结果对m取模

解题思路

首先我们可以明确的是n分成的这几个数字必然是互质的,为什么? 假设有两个数字a和b不互质,那么两者的gcd必然不为1,求LCM是必然会少乘以一个两者的gcd,最后的解也就肯定不是最优解了。而对于多个互质的数,最小公倍数是他们的乘积, 所以我们可以先筛选出1~3000的素数,然后从这些素数里面取或者多个组成n,最后求n填满时最大的LCM

发现什么了吗? 是不是很像完全背包? 没错,这里就是用的完全背包。

只不过跟一般的完全背包不同的是一般的背包取k件相同物品(体积和价值为p),体积和价值都是p*k,而这里因为p是n的约数,两个p意味着一个合数p*p

所以这里需要对n~小于等于n的某个素数做一次比较,当体积价值为p,p^1,p^3...p^k时最大的ans[i]

注意这道题运算过程中会溢出,而又不能随时取模,随时取模会导致比较最大值时出错。 所以我们可以令设一个数组,将乘法转换为加法。同时维护两个数组即可

代码部分

#include <iostream>  
#include <cstdio>  
#include <cstring>  
#include <algorithm>  
#include <cmath>  
using namespace std;  
#define N 3500  
#define LL long long  
double dp[N];  
LL ans[N];  
LL prime[N],notprime[N];  
LL gcd(LL a,LL b)  
{  
    return b?gcd(b,a%b):a;  
}  
void init()  
{  
    prime[0]=0;  
    for(int i=2;i<=3000;i++)  
    {  
        if(!notprime[i])  
        {  
            prime[++prime[0]]=i;  
            for(LL j=(LL)i*i;j<=3000;j+=i)  
                notprime[j]=1;  
        }  
    }  
}  
int main()  
{  
    int n,m;  
    init();  
    while(scanf("%d %d",&n,&m)!=EOF)  
    {  
        for(int i=0;i<=n;i++)  
            {  
                dp[i]=0;  
                ans[i]=1;  
            }  
         for(LL i=1;i<=prime[0]&&prime[i]<=n;i++)  
         {  
             double tmp=log(prime[i]*1.0);  
             for(LL j=n;j>=prime[i];j--)  
             {  
                 for(LL k=prime[i],q=1;k<=j;k*=prime[i],q++)  
                 {  
                     if(dp[j-k]+q*tmp>dp[j])  
                     {  
                         dp[j]=dp[j-k]+q*tmp;  
                         ans[j]=ans[j-k]*k%m;  
                     }  
                 }  
             }  
         }  
        printf("%lld\n",ans[n]);  
    }  
    return 0;  
}  

文章转载

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值