HDU3092-Least common multiple(数据划分+背包)

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

Hint: you can divied 6 as 1+2+3 and the LCM(1,2,3)=6 is the largest so we output 6%23=6.

分析:

题意:
将一个数n划分为几个数,这几个数的和为n,求这几个数的最小公倍数的最大值(因为n的划分方法不同,他的最小公倍数可能不同)!最后得结果对m取模!

解析:
要求的最小公倍数,那么这几那么我们把这n划分为几个互斥的数,那么此时几个数的乘积便是最小公倍数,在比较所有不同划分方法所得值得大小取最大值即是n得最小公倍数得最大值!

这里我们考虑到几个互斥得数得乘积比较大,所以想到了每次相乘后都对m取模,但是这样会在中间大小比较的时候出错,所以看了大佬们的取对数!
即:
log(ab)=log(a)+log(b);
结果的大小关系没有发生变化,但是数量级却变小很多!

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define N 3005

using namespace std;

int Prime[N<<2];
bool vist[N];
double dp[N];
int result[N];

int main()
{
	int n,m;
	memset(vist,true,sizeof(vist));
	Prime[0]=0;
	for(int i=2;i<=3000;i++)
	{
		if(vist[i])
		{
			Prime[++Prime[0]]=i;
			for(int j=i;j<=3000;j+=i)
			{
				vist[j]=false;
			}
		}
	}
	while(~scanf("%d%d",&n,&m))
	{
		for(int i=0;i<=n;i++)
		{
			dp[i]=0;
			result[i]=1;
		}
		for(int i=1;i<=Prime[0]&&Prime[i]<=n;i++)
		{
			double logarithm=log(Prime[i]*1.0);
			for(int j=n;j>=Prime[i];j--)
			{
				for(int k=Prime[i],p=1;k<=j;k*=Prime[i],p++)
				{
					if(dp[j]<dp[j-k]+p*logarithm)
					{
						dp[j]=dp[j-k]+p*logarithm;
						result[j]=((result[j-k]%m)*(k%m))%m;
					}
				}
			}
		}
		printf("%d\n",result[n]);
	}
	return 0;
}
发布了64 篇原创文章 · 获赞 17 · 访问量 877

猜你喜欢

转载自blog.csdn.net/weixin_43357583/article/details/105302286