反素数应用 ZOJ 2562 More Divisors + Timus OJ 1748. The Most Complex Number

More Divisors

Time Limit: 2 Seconds       Memory Limit: 65536 KB

Everybody knows that we use decimal notation, i.e. the base of our notation is 10. Historians say that it is so because men have ten fingers. Maybe they are right. However, this is often not very convenient, ten has only four divisors -- 1, 2, 5 and 10. Thus, fractions like 1/3, 1/4 or 1/6 have inconvenient decimal representation. In this sense the notation with base 12, 24, or even 60 would be much more convenient.

The main reason for it is that the number of divisors of these numbers is much greater -- 6, 8 and 12 respectively. A good quiestion is: what is the number not exceeding n that has the greatest possible number of divisors? This is the question you have to answer.

Input:

The input consists of several test cases, each test case contains a integer n (1 <= n <= 1016).

Output:

For each test case, output positive integer number that does not exceed n and has the greatest possible number of divisors in a line. If there are several such numbers, output the smallest one.

Sample Input:
10
20
100
Sample Output:
6
12
60


题意:给定一个数n,要求一个不超过n的数,并且因子数最多的最小的数。

思路:在之前我们先看一下反素数的概念。 http://blog.csdn.net/acdreamers/article/details/25049767

根据反素数的定义,会有如下两个性质。 反素数一定的因子一定是连续的质数,因为根据定义可以看出,如果x是反素数,那么他的因子数比任何一个小于它的数都要大,并且这个x是最小的。假设质数不是连续的,我们可以将最大的那个素数全部“填补”到断开那里,这样因子数不会变大,但是x确变小了。所以上述性质成立。 还有另外一个性质就是各个因子的指数是不升的。 可以用同样的方法证明。

有这些知识有什么用呢? 我们看看题目要求什么,就是不超过n的最大的反素数。是吧?怎么求呢?上面的链接里面说了搜索。 我们来看看是怎么搜的。 我们先得出一个足够长的素数表,由于是反素数,所以这需要这些素数连乘起来刚好超过题目给定的范围就行了。 然后我们开始枚举每个质因子的指数,在搜索的过程中不断的更新答案就行了。还有就是如果枚举因子指数的过程中,如果数字已经超过了n,就可以不用继续枚举了,因为后面枚举下去都是超过n的。到这里这道题目进本能解决了。


代码:

#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
#define LL unsigned long long
int pri[]={2, 3, 5, 7, 11, 13, 17, 19, 23, 29 ,31, 37, 41, 43, 47, 53 ,59 ,61, 67, 71, 73, 79, 83, 89, 97};
LL n;
LL cnt,ans;

void dfs(int dep,LL num,LL x)
{
    if(x>n) return;
    if(num>cnt) { cnt=num; ans=x; }
    else if(num==cnt) {
        if(x<ans) ans=x;
    }
    for(LL i=1;i<63;++i) {
        if(x>n/pri[dep]) break;
        dfs(dep+1,num*(i+1),x*=pri[dep]);
    }
}

int main()
{
    while(scanf("%lld",&n)==1) {
        cnt=0,ans=n;
        dfs(0,1,1);
        cout<<ans<<endl;
    }
}


1748. The Most Complex Number

Time limit: 1.0 second
Memory limit: 64 MB
Let us define a  complexity of an integer as the number of its divisors. Your task is to find the most complex integer in range from 1 to  n. If there are many such integers, you should find the minimal one.

Input

The first line contains the number of testcases  t (1 ≤  t ≤ 100). The  i-th of the following  t lines contains one integer  ni  (1 ≤  ni ≤ 10 18) .

Output

For each testcase output the answer on a separate line. The  i-th line should contain the most complex integer in range from 1 to  ni and its complexity, separated with space.

Sample

input output
5
1
10
100
1000
10000
1 1
6 4
60 12
840 32
7560 64
Problem Author: Petr Lezhankin
Problem Source: Ufa SATU Contest. Petrozavodsk Summer Session, August 2009


跟上面那题一样。写法上我利用第二条性质我改进了一下。


代码:

#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
#define LL unsigned long long
int pri[]={2, 3, 5, 7, 11, 13, 17, 19, 23, 29 ,31, 37, 41, 43, 47, 53 ,59 ,61, 67, 71, 73, 79, 83, 89, 97};
LL n;
LL cnt,ans;

void dfs(int dep,LL num,LL val,int tail)
{
    if(num>cnt) { cnt=num; ans=val; }
    else if(num==cnt&&ans>val) ans=val;
    for(LL i=1;i<=tail;++i) {
        if(val>n/pri[dep]) break;
        dfs(dep+1,num*(i+1),val*=pri[dep],i);
    }
}

int main()
{
    int _; cin>>_;
    while(_--) {
        cin>>n;
        ans=n; cnt=0;
        dfs(0,1,1,64);
        cout<<ans<<" "<<cnt<<endl;
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值