hdu 3092 Least common multiple

思路:

容易知道,分解成素数的lcm肯定是最大的,因为假设分解成2个合数,设定x为他们的 最大公约数,

那么他们的最小公倍数就要减少x倍了
然后如果是素数之间的最小公倍数,那么就只是他们的乘积,同样的n分解,没有 除的肯定比有除的大,

因此可以得到结论 所以可以先晒一次素数,然后用这些素数填满那个n
这里填满也很容易想到是背包问题了,因为同一个素数可以用几次,所以就是一个 典型的多重背包了,

就是dp[j] = lcm(dp[j - k] , dp[k]);
然后还有一个问题,就是对于所有素数取lcm,会导致结果很大,超int的 而且虽然有取mod,

那么转移方程变为dp[j] = dp[j - k] * w * prime[i]; 都是乘法运算,那么我们就可以利用取对数,

把乘法运算转成加法来判断了就行了 然后另开一个数组,用来取mod的,最后结果就是dp[n]了

代码如下:

 

 1 #include<cstdio>

 2 #include<vector>

 3 #include<iostream>

 4 #include<cstring>

 5 #include<algorithm>

 6 #include<cmath>

 7 #define M 10005

 8 using namespace std;

 9 double dp[M];

10 int p[M];

11 int prime[M],cnt,n;

12 bool f[M];

13 void init()

14 {

15     cnt=0;

16     for(int i=2;i<M;i++){

17         if(!f[i]) prime[cnt++]=i;

18         for(int j=0;j<cnt&&i*prime[j]<M;j++){

19             f[i*prime[j]]=1;

20             if(i%prime[j]==0) break;

21         }

22     }

23 }

24 void solve(int m)

25 {

26     memset(dp,0,sizeof(dp));

27     for(int i=0;i<=n;i++) p[i]=1;

28     for(int i=0;i<cnt&&prime[i]<=n;i++){

29         double t=log(prime[i]);

30         for(int j=n;j>=prime[i];j--){

31             for(int k=prime[i],num=1;k<=j;k*=prime[i],num++)

32             if(dp[j-k]+t*num>dp[j]){

33                 dp[j]=dp[j-k]+t*num;

34                 p[j]=p[j-k]*k%m;

35             }

36         }

37     }

38 }

39 int main()

40 {

41     int m;

42     init();

43     while(scanf("%d%d",&n,&m)!=EOF){

44         solve(m);

45         printf("%d\n",p[n]);

46     }

47     return 0;

48 }
View Code

 

 

 

你可能感兴趣的:(com)