反素数求解及相关题目


反素数

  1. 定义:对于任何正整数n,其约数个数记为f(n),例如f(6)=4;如果存在一个正整数n满足:对于任意的正整数x(0<x<n),都有f(x)<f(n)成立,那么把n称为反素数。

    1. 一个反素数的所有质因子必然是从2开始的若干个质数,因为一个数是反素数,说明在跟它约数相同的数中,它是最小的。
    2. 如果n=2t1 * 3t2 * 5t3 *...,那么一定有t1>=t2>=t3>=t4... 另外易知如果n=2t1* 3t2 * 5t3 * ...,那么n的约数个数为(t1+1) *(t2+1) * (t3+1)...


由性质可知,我们进行反素数相关运算的方法是从小到大枚举每个质因子(素数)进行DFS

一般题目的代码模板见下

void dfs(ll num,int k,int sum,int limit)
{//num: 当前枚举到的数 k:枚举到的第k大的质因子 sum:该数的约数个数 limit:质因子个数上限(重要剪枝)
    if(sum>maxsum)       //约数个数更多
    {
        maxsum=sum;
        ans=num;
    }
    if(sum==maxsum&&ans>num)  //约数个数相同,把最优解更新为较小值
    {
        ans=num;
    }
    if(k>16)                     //这里k>x; x至少满足prime[1]*prime[2]*prime[3]*...*prime[x]>x ,当x=16时,数据已超过10^18
        return;                  //当x=10时,数据已超过10^9
    ll temp=num;
    for(int i=1;i<=limit;i++)  //枚举每个质因子的个数
    {
        if(n/prime[k]<temp)    //n为上限,用除法防止溢出
            return;
        temp*=prime[k];
        dfs(temp,k+1,sum*(i+1),i);  //把limit置为i的原因见性质第二条
    }
}


下面附上几道关于反素数的题目


1.HDOJ 4133

StrangeStandard

TimeLimit: 2000/1000 MS (Java/Others)    Memory Limit:32768/32768 K (Java/Others)
Total Submission(s): 331    Accepted Submission(s): 176

Problem Description

Nowadays,WHUACMer use a strange standard to evaluate a natural number.The evaluatingvalue of a natural number is the amount of it’s divisors.If a number m hasbigger evaluating value than all the numbers smaller than it, we call it a goodnumber. Now give you a number n, find the maximum good number which is notbigger than n.

 

 

Input

The first line contains a single integer T(T<=10), indicating the number of testcases.
For each test case,there is only one line which only contains one number n(1<= n <= 2 000 000 000)

 

 

Output

For each test case,output the case number first,then output the maximum good numberwhich is not bigger than n.

 

 

Sample Input

1

1000

 

 

Sample Output

Case #1: 840

题意:求出给定数范围内最大的反素数,即求该范围内约数最多(尽可能小)的数。


#include <bits/stdc++.h>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define f(i,a,b) for(int i=(a);i<(b);++i)
typedef long long ll;
const int maxn= 40005;
const int mod = 475;
const ll INF = 0x3f3f3f3f;
const double eps = 1e-6;
#define rush() int T;scanf("%d",&T);while(T--)
int prime[]={1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};

ll ans,n;
int maxsum;

void dfs(ll num,int k,int sum,int limit)
{
    if(sum>maxsum)
    {
        maxsum=sum;
        ans=num;
    }
    if(sum==maxsum&&num<ans)
    {
        ans=num;
    }
    if(k>12)
        return;
    ll temp=num;
    for(int i=1;i<=limit;i++)
    {
        if(n/prime[k]<temp)
            return;
        temp*=prime[k];
        dfs(temp,k+1,sum*(i+1),i);
    }
}

int main()
{
    int cas=1;
    rush()
    {
        scanf("%I64d",&n);
        ans=INF*INF;
        maxsum=0;
        dfs(1,1,1,35);
        printf("Case #%d: %I64d\n",cas++,ans);
    }
    return 0;
}


2.  Codeforces Beta Round #27 (Codeforces format, Div. 2)



E. Number With The Given Amount Of Divisors

time limit per test 2seconds

memory limit per test 256megabytes

Given the numbern, find the smallest positive integerwhich has exactly n divisors. It is guaranteed that for the given n the answer will not exceed 1018.

Input

The first line of the input contains integern (1 ≤ n ≤ 1000).

Output

Out put the smallest positive integer with exactlyn divisors.

Examples

Input

4

Output

6

Input

6

Output

12

 


题意:输出约数个数为n的最小数


#include <bits/stdc++.h>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define f(i,a,b) for(int i=(a);i<(b);++i)
typedef long long ll;
const int maxn1= 40005;
const int mod = 475;
const ll INF = 0x3f3f3f3f;
const double eps = 1e-6;
#define rush() int T;scanf("%d",&T);while(T--)
int prime[]={1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
ll ans;
int n;

void dfs(ll num,int k,int sum,int limit)
{//num: 当前枚举到的数 k:枚举到的第k大的质因子 sum:该数的约数个数 limit:质因子个数上限(重要剪枝)
    if(sum>n)              //这里要注意,当约数大于n时,这个值应舍去
        return;
    if(sum==n&&num<ans)
        ans=num;
    if(k>16)
        return;
    ll temp=num;
    for(int i=1;i<=limit;i++)
    {
        if(ans/prime[k]<temp)
            return;
        temp*=prime[k];
        dfs(temp,k+1,sum*(i+1),i);
    }
}

int main()
{
    while(~scanf("%d",&n))
    {
        ans=INF*INF;
        dfs(1,1,1,64);
        printf("%I64d\n",ans);
    }
    return 0;
}


3. HDOJ 2521


反素数

TimeLimit: 2000/1000 MS (Java/Others)    Memory Limit:32768/32768 K (Java/Others)
Total Submission(s): 6653    Accepted Submission(s): 3971

Problem Description

反素数就是满足对于任意i(0<i<x),都有g(i)<g(x),(g(x)是x的因子个数),则x为一个反素数。现在给你一个整数区间[a,b],请你求出该区间的x使g(x)最大。

 

 

Input

第一行输入n,接下来n行测试数据
输入包括a,b,1<=a<=b<=5000,表示闭区间[a,b].

 

 

Output

输出为一个整数,为该区间因子最多的数.如果满足条件有多个,则输出其中最小的数.

 

 

Sample Input

3

2 3

1 10

47 359

 

 

Sample Output

2

6

240

Hint

 

2的因子为:1 2

10的因子为:1 25 10



这道题神坑啊,,,描述了反素数的定义,然而却跟反素数没有任何关系,反而会造成误导,仔细观察可知,要求的是区间内约数最多的数,因为只是一个区间,所以这个是并不一定是反素数,自然不能用反素数的方法去求(比如在区间内到了一个约数最多的数x,但在这个区间前如果也有一个比它小的数跟x的约数个数相同,那么x自然不是反素数)

由于数据范围较小,可以无脑暴力求,这里不贴代码,贴上我经过改动求反素数的模板后的AC代码

#include <bits/stdc++.h>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define f(i,a,b) for(int i=(a);i<(b);++i)
typedef long long ll;
const int maxn= 40005;
const int mod = 475;
const int INF = 0x3f3f3f3f;
const double eps = 1e-6;
#define rush() int T;scanf("%d",&T);while(T--)
int prime[]={1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
int ans,maxsum;
int n,m;

void dfs(int num,int k,int sum)  //首先,因为不一定是反素数,先去掉根据反素数性质加上的剪枝
{
    if(sum>maxsum&&num>=n)
    {
        maxsum=sum;
        ans=num;
    }
    if(sum==maxsum&&ans>num&&num>=n)
    {
        ans=num;
    }
    if(k>8)
        return;
    int temp=num;
    for(int i=1;;i++)
    {
        if(m/prime[k]<temp)
            return;
        temp*=prime[k];
        dfs(temp,k+1,sum*(i+1));
    }
}

int main()
{
    rush()
    {
        scanf("%d%d",&n,&m);
        ans=INF;
        maxsum=0;
        dfs(1,1,1);
        if(n==m)               //由于每次dfs时至少乘一次质因子,所以有的数就无法搜到
            ans=n;             //举个例子 输入 5 5,由于先乘了2,再乘3,就超过了5,结束,没有得到正确结果,故需要特判
        printf("%d\n",ans);
    }
    return 0;
}



4. HDOJ 4228


Flooring Tiles

TimeLimit: 2000/1000 MS (Java/Others)    Memory Limit:32768/32768 K (Java/Others)
Total Submission(s): 448    Accepted Submission(s): 212

Problem Description

You want to decorate your floor with square tiles. You like rectangles. With sixsquare flooring tiles, you can form exactly two unique rectangles that use allof the tiles: 1x6, and 2x3 (6x1 is considered the same as 1x6. Likewise, 3x2 isthe same as 2x3). You can also form exactly two unique rectangles with foursquare tiles, using all of the tiles: 1x4, and 2x2.
Given an integer N, what is the smallest number of square tiles needed to beable to make exactly N unique rectangles, and no more, using all of the tiles?If N=2, the answer is 4.

 

 

Input

There will be several test cases in the input. Each test case will consist of asingle line containing a single integer N (1 ≤ N ≤ 75), which represents thenumber of desired rectangles. The input will end with a line with a single 0.

 

 

Output

For each test case, output a single integer on its own line, representing thesmallest number of square flooring tiles needed to be able to form exactly Nrectangles, and no more, using all of the tiles. The answer is guaranteed to beat most 10^18. Output no extra spaces, and do not separate answers with blanklines.

 

 

Sample Input

2

16

19

0

 

 

Sample Output

4

840

786432

 

题意:有一些相同的正方形,现问如果要拼出n种不同的长方形最少需要的正方形个数。 思路:稍作分析可知求的是约数个数为2 * n的最小整数,但还要考虑拼出是特殊的长方形(如n=2,只要找约数个数为3的4,因为4为完全平方数,2 * 2也能拼出一个),综上所述,我们要找的是约数个数为 2 * n或2 * n - 1的最小整数(这两个数不一定存在)。


#include <bits/stdc++.h>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define f(i,a,b) for(int i=(a);i<(b);++i)
typedef long long ll;
const int maxn= 160;
const int mod = 475;
const ll INF = 0x3f3f3f3f;
const double eps = 1e-6;
#define rush() int T;scanf("%d",&T);while(T--)
int prime[]={1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};

ll arr[maxn];
ll ans[maxn];

void dfs(ll num,int k,int sum,int limit)
{
    if(sum>maxn) return;       //注意加上返回条件,否则数组会越界
    if(arr[sum]==0||(arr[sum]!=0&&num<arr[sum]))
    {
        arr[sum]=num;
    }
    if(k>16)
        return;
    ll temp=num;
    for(int i=1;i<=limit;i++)
    {
        if(INF*INF/prime[k]<temp)
            return;
        temp*=prime[k];
        dfs(temp,k+1,sum*(i+1),i);
    }
}

int main()
{
    mst(arr,0);
    mst(ans,0);
    dfs(1,1,1,65);
    for(int i=1;i<=75;i++)
    {
        if(arr[2*i]&&arr[2*i-1])
        {
            ans[i]=min(arr[2*i],arr[2*i-1]);
        }
        else if(arr[2*i])
        {
            ans[i]=arr[2*i];
        }
        else
        {
            ans[i]=arr[2*i-1];
        }
    }
    int n;
    while(~scanf("%d",&n)&&n)
    {
        printf("%I64d\n",ans[n]);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值