在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;
}
}