您的位置:首页 > 其它

ACM-反素数

2014-11-02 14:38 85 查看
这篇文章将讨论反素数,素数大家都知道是什么,那么什么又是反素数呢?

先看定义:对于任何一个整数n,将其约数的个数记为g(n),如g(1) = 1,g(6) = 4,并且如果对于任何一个整数i (0<i<n),都满足g(i) < g(n) ,那么我们称n为反素数。

再看性质:1、一个反素数的质因子必然是从2开始的连续质数。

2、如果反素数n = 2^a * 3^b * 5^c * 7^d * ......,那么必然a >= b >= c >= d。

最后看一下ACM中有关反素数的一般题型:

1、找出不大于n的最大反素数。

2、找出不大于n的约数个数最多的数(与1等价)。

3、找出一个约数个数为n的最小数。

解题思路:结合反素数的定义及性质,最基本的原理是以2、3、5、......建立搜索树,枚举每一个质因子,然后判断记录。

下面源代码中德AntiPrime
代表约数个数为n的最小数:

using namespace std;
typedef __int64 lld;

lld AntiPrime[1010];
lld prime[30]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};

void GetAntiPrime(lld cur, int cnt, int limit, int k)
{
//cur:当前枚举到的数
//cnt:该数的因数个数
//limit:因数个数的上限,2^t1*3^t2*5^t3……t1>=t2>=t3……
//k:第k大的素数
if(cur>((lld)1<<60) || cnt>150) return;
if(AntiPrime[cnt]!=0 && AntiPrime[cnt]>cur)  // 当前的因数个数已经记录过且当时记录的数比当前枚举到的数要大,则替换此因数个数下的枚举到的数
AntiPrime[cnt] = cur;
if(AntiPrime[cnt] == 0)                      // 此因数个数的数还没有出现过,则记录
AntiPrime[cnt] = cur;
lld temp = cur;
for(int i=1; i<=limit; i++)                  // 枚举数
{
temp = temp*prime[k];
if(temp > ((lld)1<<60)) return;
GetAntiPrime(temp, cnt*(i+1), i, k+1);
}
}


下面是一道相关的例题,HDOJ:4228,时空转移(点击打开链接),题目如下:


Flooring Tiles

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 347 Accepted Submission(s): 137



Problem Description

You want to decorate your floor with square tiles. You like rectangles. With six square flooring tiles, you can form exactly two unique rectangles that use all of the tiles: 1x6, and 2x3 (6x1 is considered the same as 1x6. Likewise, 3x2 is the same as 2x3).
You can also form exactly two unique rectangles with four square tiles, using all of the tiles: 1x4, and 2x2.

Given an integer N, what is the smallest number of square tiles needed to be able 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 a single line containing a single integer N (1 ≤ N ≤ 75), which represents the number 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 the smallest number of square flooring tiles needed to be able to form exactly N rectangles, and no more, using all of the tiles. The answer is guaranteed to be at most 10^18. Output
no extra spaces, and do not separate answers with blank lines.

Sample Input

2
16
19
0


Sample Output

4
840
786432


题意:

有一些相同的正方形,可以拼出n种不同的长方形,现问如果要拼出n种长方形最少需要的正方形个数。

分析:

可以感觉到,有可能有关整数n的因子,因为都是组成的关系嘛,再仔细一想,其实就是求约数个数为2*n或者2*n-1的最小整数。

源代码:

#include<cstdio>
#include<algorithm>
#include<cmath>

using namespace std;
typedef __int64 lld;

lld AntiPrime[1010];
lld prime[30]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};

void GetAntiPrime(lld cur, int cnt, int limit, int k)
{
if(cur>((lld)1<<60) || cnt>150) return;
if(AntiPrime[cnt]!=0 && AntiPrime[cnt]>cur)
AntiPrime[cnt] = cur;
if(AntiPrime[cnt] == 0)
AntiPrime[cnt] = cur;
lld temp = cur;
for(int i=1; i<=limit; i++)
{
temp = temp*prime[k];
if(temp > ((lld)1<<60)) return;
GetAntiPrime(temp, cnt*(i+1), i, k+1);
}
}

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


其它相关的题目还有,HDOJ:4133,4392,4542。ZOJ:1562,2562。CODEFORCE:27E。

接下来,我们将讨论欧拉函数,传送门(点击打开链接)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: