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.
题意:将一个数拆分成几个数的和,并求出这几个数最小公倍数的乘积的最大值模M后的值。
思路:
最小公倍数乘积最大,所以当这几个数都互质的,也就是都是素数的时候,他们的lcm最大。
所以可以先筛出素数,然后进行完全背包,不过乘积范围很大,所以要用一种特殊的方式
就是取log,将乘法变成加法,用这个数组来维护当前位置最大值,然后用另外一个数组,维护结果。
ac代码:
/*
要不要选看dp数组,
ans数组还是正常的乘法(结果值),dp数组是取Log后的值 (用来比较的值)
正常的转移方程应该是 dp[j]=max(dp[j],dp[j-prime[i]]*k*prime[i]);
但是这样有可能会爆longlong,所以取了一个log,把乘法变成了加法,
而且答案是要取余的值直接比较Max是不对的,
所以分了两个数组一个用来比较大小,一个 用来存储结果。
之后的转移方程就变成了,dp[j]=max(dp[j],dp[j-prime[i]]+k*prime[i])
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<vector>
using namespace std;
typedef long long ll;
const int MAXN=10000;
int prime[MAXN];
void init()
{
for(int i=2;i<=MAXN;i++)
{
if(!prime[i]) prime[++prime[0]]=i;
for(int j=1;j<=prime[0]&&prime[j]<=MAXN/i;j++)
{
prime[prime[j]*i]=1;
if(j%prime[j]==0) break;
}
}
}
ll ans[10000];
double dp[10000];
int main()
{
init();
int s,m;
while(~scanf("%d%d",&s,&m))
{
for(int i=0;i<=s;i++)
{
dp[i]=0;
ans[i]=1;
}
for(int i=1;i<=prime[0];i++)//完全背包
{
if(prime[i]>s)break;
for(int j=s;j>=prime[i];j--)
{
double tmp=log(prime[i]*1.0);
for(int p=prime[i],q=1;p<=j;p*=prime[i],q++)
{
if(dp[j-p]+q*tmp>dp[j])
{
dp[j]=dp[j-p]+q*tmp;
ans[j]=(ans[j-p]*p)%m;
}
}
}
}
printf("%lld\n",ans[s]);
}
return 0;
}