HDU - 3092 Least common multiple (数论+背包)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3092点击打开链接

Least common multiple

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1036    Accepted Submission(s): 433


Problem Description
Partychen like to do mathematical problems. One day, when he was doing on a least common multiple(LCM) problem, he suddenly thought of a very interesting question: if given a number of S, and we divided S into some numbers , then what is the largest LCM of these numbers? partychen thought this problems for a long time but with no result, so he turned to you for help!
Since the answer can very big,you should give the answer modulo M.
 

Input
There are many groups of test case.On each test case only two integers S( 0 < S <= 3000) and M( 2<=M<=10000) as mentioned above.
 

Output
Output the largest LCM modulo M of given S.
 

Sample Input
 
  
6 23
 

Sample Output
 
  
6

给出n,m

求正整数和为n所有情况中最大的lcm的值模m

对于n 只有小于他的质数和质数的幂对lcm有贡献 一开始不理解为什么是幂而不是倍数 因为如果是倍数说明还存在其他的因子 这使得在对物品划分的时候会产生影响

我们把n中所有的质数划分出来 进行01背包 

 注意这里是质数进行01背包 而不包含质数的幂 

原因在于相同质数为底的不同幂次间不互质(第一个样例中 如果2与4同时存在 他们的lcm!=2*4)

01背包中再加一层循环 枚举质数的幂次 这样就保证了不会出现上面的情况 

另外注意因为直接相乘的结果很大 同时不能在dp时取模 用对数是个很巧妙的办法 保证大小关系不变的同时 减小数据量

#include<bits/stdc++.h>
using namespace std;
long long int prime[3333];
void init()
{
    for(long long int i=2;i<3333;i++)
    {
        if(prime[i]==0)
        {
            for(long long int j=i*2;j<3333;j+=i)
            {
                prime[j]=1;
            }
        }
    }
}
vector<long long int >s;
double dp[3333];
long long int ans[3333];
int main()
{
    init();
    for(long long int i=2;i<3333;i++)
    {
        if(prime[i]==0)
        {
            s.push_back(i);
        }
    }
    long long int len=s.size();
    long long int n,m;
    while(scanf("%lld%lld",&n,&m)!=EOF)
    {
        memset(dp,0,sizeof(dp));
        for(int i=0;i<=n;i++)
            ans[i]=1;
        double mid=-1;
        long long int anss=1;
        for(long long int i=0;i<len;i++)
        {
            for(long long int j=n;j>=s[i];j--)
            {
                for(int k=s[i];k<=j;k*=s[i])
                if(dp[j]<dp[j-k]+log10(k))
                {
                    dp[j]=dp[j-k]+log10(k);
                    ans[j]=ans[j-k]*k%m;
                }
            }
        }
        for(int i=0;i<=n;i++)
        {
            if(mid<dp[i])
            {
                mid=dp[i];
                anss=ans[i];
            }
        }
        printf("%lld\n",anss);
    }
}





猜你喜欢

转载自blog.csdn.net/xuejye/article/details/80274052