浅谈反素数

        在poj 上做2886的时候发现要使用反素数,还有大神说这题是约瑟夫环的升级版,一个都没听说过的我只好分别去脑补了一下~~~~

    呃,言归正传,先说说什么是反素数。

   反素数的定义:对于任何正整数,其约数个数记为,例如,如果某个正整数满足:对任意的正整,都有,那么称为反素数。

从反素数的定义中可以看出两个性质:

    (1)一个反素数的所有质因子必然是从2开始的连续若干个质数。这个性质严格的数学证明我也不知道,但细思一下还是能理解的。例如如果不是连续的质因子,而是n=2^t1 * 5^t2 *....  那么必然有x<n,且x=2^r1 * 3^r2 * ....或 x=2^r1.... 显然,(r1+r2)>(t1+t2) 或 r1>(t1+t2)。而我们知道:

        12=2^2 * 3^1, 其因子个数则为(2+1)*(1+1)=6个。这个结论在下面的题中也会用到。

    (2)如果,那么必有

   在题目中经常会遇到的问题有两种:

   (1)求n以内最大的反素数,即n以内因子个数最多的数。

   (2)求一个最小整数x,其因子个数恰好为n。

    针对第一个问题,暴力的方法自然是枚举1至n里每一个数的因子数目,找最大的那个,但当n很大时,显然就行不通了。于是我们需要减少枚举的情况。具体在于用讲性质1证明时的那个结论和性质1本身作为基础,递归枚举1至n里的数(其实这一步已经做到一定的剪枝,因为有些数已经直接跳过),接着再用反素数的性质二做进一步剪枝。具体实现在代码里有注释。

hdu 4133:

   求n以内最大反素数,有相同时输出最小的那个。

   

#include <cstdio>
#include <stack>
#include <set>
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <list>
#include <functional>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <string>
#include <map>
#include <iomanip>
#include <cmath>
#define LL long long
#define ULL unsigned long long
#define SZ(x) (int)x.size()
#define Lowbit(x) ((x) & (-x))
#define MP(a, b) make_pair(a, b)
#define MS(arr, num) memset(arr, num, sizeof(arr))
#define PB push_back
#define F first
#define S second
#define ROP freopen("input.txt", "r", stdin);
#define MID(a, b) (a + ((b - a) >> 1))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define lrt rt << 1
#define rrt rt << 1|1
#define root 1,n,1
#define BitCount(x) __builtin_popcount(x)
#define BitCountll(x) __builtin_popcountll(x)
#define LeftPos(x) 32 - __builtin_clz(x) - 1
#define LeftPosll(x) 64 - __builtin_clzll(x) - 1
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
using namespace std;
const double eps = 1e-5;
const int MAXN = 300 + 10;
const int MOD = 1000007;
const double M=1e-8;
const int N=1e6+10;
typedef pair<int, int> pii;
typedef pair<int, string> pis;
const int d[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
int p[22] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};
int m,st[N],lazy[N];
bool vis[N];
LL n,maxnum,morenum;
// 第k个质因子,n = 2^t1 * 3^t2 * 5^t3 * .... , t1>=t2>=t3>=....
// num 当前枚举到的数
// sum num的质因子数目
// limit 质因子数目上限,根据反素数性质二而进行的剪枝
void dfs(int k,LL num,LL sum,int limit)
{
    if (num>n) return ;
    if (sum>morenum) {   // 因子个数更多
        maxnum=num;
        morenum=sum;
    }
    else if (sum==morenum && num<maxnum) {  // 因子个数相同时,取更小的数
        maxnum=num;
    }
    LL t=num;
    for (int i=1;i<=limit;i++) {  // 递归枚举,以每一个pi为一层,建立搜索树
        if (t*p[k]>n) break;
        t*=p[k];
        dfs(k+1,t,sum*(i+1),i);
    }
}
int main()
{
    int i,j;
    int cnt=1;
    int t;
    cin>>t;
    while(t--)
    {
        scanf("%lld",&n);
        maxnum=INF;
        morenum=0;
        dfs(0,1,1,ceil(log2(n)) );// <span style="font-family: SimSun;">ceil(log2(n))表示n最多有多少个因子</span>
        printf("Case #%d: %lld\n",cnt++,maxnum);
    }
}























    题目:http://codeforces.com/problemset/problem/27/E

      题意:给一个数n,求一个最小整数x,使它的因子个数为n。

      同上题差不多。

#include <cstdio>
#include <stack>
#include <set>
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <list>
#include <functional>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <string>
#include <map>
#include <iomanip>
#include <cmath>
#define LL long long
#define ULL unsigned long long
#define SZ(x) (int)x.size()
#define Lowbit(x) ((x) & (-x))
#define MP(a, b) make_pair(a, b)
#define MS(arr, num) memset(arr, num, sizeof(arr))
#define PB push_back
#define F first
#define S second
#define ROP freopen("input.txt", "r", stdin);
#define MID(a, b) (a + ((b - a) >> 1))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define lrt rt << 1
#define rrt rt << 1|1
#define root 1,n,1
#define BitCount(x) __builtin_popcount(x)
#define BitCountll(x) __builtin_popcountll(x)
#define LeftPos(x) 32 - __builtin_clz(x) - 1
#define LeftPosll(x) 64 - __builtin_clzll(x) - 1
const double PI = acos(-1.0);
const ULL INF =1e18+10;
using namespace std;
const double eps = 1e-5;
const int MAXN = 300 + 10;
const int MOD = 1000007;
const double M=1e-8;
const int N=1e6+10;
typedef pair<int, int> pii;
typedef pair<int, string> pis;
const int d[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
int p[22] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};
int n,st[N],lazy[N];
bool vis[N];
ULL ans,moresum;
void dfs(int k,ULL num,ULL sum,int limit)
{
    int i,j;
    if (sum>n) return ;
    if (sum==n) {
        ans=min(ans,num);
    }
    ULL t=num;
    for (i=1;i<=limit;i++) {
        if (ans/p[k]<num) break;
        t*=p[k];
        dfs(k+1,t,sum*(i+1),i);
    }
}
int main()
{
    int i,j;
    while(~scanf("%d",&n))
    {
        ans=INF;
        dfs(0,1,1,64);
        cout<<ans<<endl;
    }
}






















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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值