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

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.

题目大意是,将一个数拆成若干数的和,然后对这些若干数求最小公倍数。求最小公倍数的最大值。

首先假设对于一个数x,我已经拆成若干数了。

对于其中两个数a和b。如果这两个数有最大公约数k。

那么这两个数个最小公倍数为a*b/k。

但是如果是a和b/k,最小公倍数依旧为a*b/k。但是两数的和更小了。这样我就可以多加一个数b-b/k,可能会使最终结果更大。

所以得到的第一个结论是,我尽量保证两两数都是互素的。

接下来,我要证明,每个数都应该是p^t的形式,p为素数。

因为当a > 1 &&
b > 1时,

(a-1)(b-1) >= 1。

即ab >= a+b。

同理来两次得到abc >= ab+c
>= a+b+c

所以,如果一个数y = p^t1*q^t2*c。p和q均为素数,且(p, q) =
(p, c) = (q, c) = 1。

那么我把拆成p^t1和q^t2和c,这三个数的最小公倍数就是y。但是这三个数的和更小了,可以再加入一个数y-p^t-q^t-c,可能会使结果更大。

所以,最终结论x = 2^c1 + 3^c2 +
5^c3 + ...,底数为素数。

到这里做法就比较多了。

有一种做法是用直接用dfs暴力搜索。

枚举对于一个素数p,加上p^i。

dfs(int now, int sum, BigInteger val)

这里now表示枚举到第几个素数,sum表示当前情况的和是多少,val表示当前最小公倍数。

这样一开始传入s,到了第二层递归树,分别为0, 2, 4,
8…,

对于2下方的一层是2, 2+3, 2+9…

首先3000以内素数有430个左右。层数可能会达到430层,就算不是满枝,复杂度也很大。

既然这样,

于是考虑p[i]数组表示i拆分的最小公倍数的最大值。

那么p[i] = max(p[i-prime[k]^t] * prime[k]^t)。

就是对于i,枚举它由i-prime[k]^t加prime[k]^t构成。然后求最值,这样之前枚举过的素数得到的最值都被记忆化了。

复杂度是:s*primeNum*log(s) ->
总和s*素数个数*枚举次方数

最差情况:3000*430*log(3000)这个复杂度不是很大,所以直接用java大数,这题也能过,不过网上也有取对数来防止数据溢出的方法。

代码:

import java.math.BigInteger;
import java.util.Scanner; public class Main
{
boolean isprime[] = new boolean[3005];
int prime[] = new int[450];
int top;
BigInteger p[] = new BigInteger[3005];
boolean vis[] = new boolean[3005];
//埃氏筛法求素数
void isPrime()
{
for (int i = 0; i < 3005; ++i)
isprime[i] = true;
isprime[0] = isprime[1] = false;//初始化
for (int i = 2; i <= 3000; ++i)//筛法
{
if (isprime[i])
{
for (int j = i*i; j <= 3000; j += i)//上界太大可能会爆int
{
isprime[j] = false;
}
}
}
top = 0;
for (int i = 0; i <= 3000; ++i)
if (isprime[i])
prime[top++] = i;
} BigInteger dp(int s)
{
BigInteger ans = new BigInteger("1");
vis[0] = true;
for (int i = 1; i <= s; ++i)
vis[i] = false;
p[0] = new BigInteger("1");
for (int i = 0; i < top && prime[i] <= s; ++i)
{
for (int j = s; j >= prime[i]; --j)
{
for (int k = prime[i]; k <= j; k *= prime[i])
{
if (j-k < 0 || !vis[j-k])
continue;
if (!vis[j])
{
p[j] = p[j-k].multiply(new BigInteger(Integer.toString(k)));
vis[j] = true;
}
else
p[j] = p[j].max(p[j-k].multiply(new BigInteger(Integer.toString(k))));
}
}
}
for (int i = 1; i <= s; ++i)
if (vis[i])
ans = ans.max(p[i]);
return ans;
} public static void main(String args[])
{
Main qt = new Main();
qt.isPrime();
BigInteger ans;
int s, m;
Scanner input = new Scanner(System.in);
while (input.hasNext())
{
s = input.nextInt();
m = input.nextInt();
ans = qt.dp(s);
System.out.println(ans.mod(new BigInteger(Integer.toString(m))));
}
}
}

最新文章

  1. Cocos2d-x 3.X 事件分发机制
  2. HTTPS Web配置举例
  3. Linux搭建apache +PHP(CentOS系统)
  4. 使用zfs进行pg的pitr恢复测试
  5. 使用cookie实现打印浏览记录的功能
  6. Ajax技术
  7. 使用Firefox user agent进行移动端网页测试
  8. 使用celery的backend异步获取结果
  9. C#与数据库访问技术总结(九)之实例
  10. 修改CSV中的某些值 -- 1
  11. mac下U盘装机系统的制作(命令行)
  12. jquery 简单弹出层(转)
  13. 一、Bitmap的recycle问题
  14. 接近带给你AngularJS - 经验说明示例
  15. 水晶报表使用经验谈--使用sql语句直接生成dataset做为报表的数据源
  16. HDU 1217 Arbitrage(Floyd的应用)
  17. 微信小程序开发教程目录
  18. css属性详解
  19. numpy pandas 索引注意事项
  20. 调用pymysql模块操作数据库

热门文章

  1. 替换jar包内指定的文件
  2. java排序(整理)
  3. 【python】-- 基于Django的杂货铺
  4. struts2中的ModelDriven使用
  5. C#读取excel 找不到可安装的ISAM
  6. wap网站即手机端网页SEO优化注意事项及方法
  7. 教你如何写一个 Yii2 扩展
  8. simple--factory--abstract
  9. 通过tile和url判断页面跳转是否正确
  10. spring项目命名