反素数
定义:对于任何正整数n,其约数个数记为f(n),例如f(6)=4;如果存在一个正整数n满足:对于任意的正整数x(0<x<n),都有f(x)<f(n)成立,那么把n称为反素数。
-
- 一个反素数的所有质因子必然是从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
#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
#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;
}