问题描述:
正整数x的约数是能整除x的正整数。正整数x 的约数个数记为div(x)。例如,1,2,5,10 都是正整数10 的约数,且div(10)=4。设a 和b 是2 个正整数,a≤b,找出a和b之间约数个数最多的数x。
编程任务:
对于给定的2个正整数a≤b,编程计算a 和 b 之间约数个数最多的数。
数据输入:
输入数据由文件名为input.txt的文本文件提供。文件的第1 行有2 个正整数 a和 b。
结果输出:
程序运行结束时,找到a 和b之间约数个数最多的那个数及最多约数个数。
测试数据:【只给出最多约数个数, time limit: 1s】
[1, 36] 9
[1000000, 2000000] 288
[999998999, 999999999] 1024
[1, 1000000000] 1344
[999999999, 1000000000] 56
[100, 1000000000] 1344
———————————————————————————————————————————————————
法一:主要就是查找一个整数的约数个数的效率问题,首先想到的是 1-√x 遍历。逐个判断。但是效率太低。
#include <iostream>
#include <fstream>
#include <ctime>
#include <cmath>
using namespace std;
ifstream fin("input.txt");
ofstream fout("output.txt");
clock_t start,finish;
double total_time;
int div(int n)
{
int num = 0;
for (int i = 1; i < sqrt((float)n); i++)
{
if (n%i == 0)
{
num += 2;
}
}
if (n == (int)sqrt((float)n)*(int)sqrt((float)n))
{
num ++;
}
return num;
}
int caculateMaxdiv(int a, int b)
{
int maxNum = 0;
for (int i = a;i <= b;i++ )
{
if ( maxNum < div(i))
{
maxNum = div(i);
}
}
return maxNum;
}
int main()
{
start = clock();
int a,b;
fin>>a>>b;
fout<<caculateMaxdiv(a,b)<<endl;
finish = clock();
total_time = (double)(finish - start)/CLOCKS_PER_SEC;
fout<<total_time<<" s"<<endl;
return 0;
}
法二:
思想:设正整数x的质因子分解为
x=p1^N1 × p2^N2 ×……pi^Ni
则 div(x)=(N1+1)(N2+1)……(Ni+1)
#include<iostream>
using namespace std;
#define max Max
const long MAXP = 100000;
long prim[MAXP];
long max, numb, PCOUNT; //max存放最多约数个数,numb存放约数个数最多的数
void primes(); //用筛选法产生质数存于prim数组中
void search(long from, long tot, long num, long low, long up);
int main()
{
primes();
long l, u;
cin >> l >> u;
if ((l == 1) && (u == 1))
{
max = 1;
numb = 1;
}
else
{
max = 2;
numb = l;
search(1, 1, 1, l, u);
}
cout << max << endl << numb << endl;
system("pause");
return 0;
}
void primes()
{
bool get[MAXP+1];
long i;
for (i = 2; i <= MAXP; i++)
get[i] = true;
for (i = 2; i <= MAXP; i++)
if (get[i])
{
long j = i + i;
while (j <= MAXP)
{
get[j] = false;
j += i;
}
}
long ii, j;
for (ii = 2, j = 0; ii <= MAXP; ii++)
if (get[ii]) prim[++j] = ii;
PCOUNT = j;
}
void search(long from, long tot, long num, long low, long up)
{
if (num >= 1)
if ( (tot > max) || ((tot == max) && (num < numb)) )
{
max = tot;
numb = num;
}
if ((low == up) && (low > num)) search(from, tot*2, num*low, 1, 1);
for (long i = from; i <=PCOUNT; i++)
{
if (prim[i] > up) return;
else
{
long j = prim[i], x = low - 1, y = up, n = num, t = tot, m = 1;
while (true)
{
m++;
t += tot;
x /= j;
y /= j;
if (x == y) break;
n *= j;
search(i+1, t, n, x+1, y);
}
m = 1 << m;
if (tot < max / m) return;
}
}
}
针对此方法的解析如下(源自网络):
法三:上述两法的中和方案。法一的思想,借用只不过用到的是法二中用筛法得到的质数表。这个更好理解一些
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX 100000
int prime[MAX];
int cnt;
//筛选法打印素数表
void Initprime(){
bool get[MAXP+1];
long i;
for (i = 2; i <= MAXP; i++)
get[i] = true;
for (i = 2; i <= MAXP; i++)
if (get[i])
{
long j = i + i;
while (j <= MAXP)
{
get[j] = false;
j += i;
}
}
long ii, j;
for (ii = 2, j = 0; ii <= MAXP; ii++)
if (get[ii]) prime[++j] = ii;
cnt= j;
}
//求数m的因子个数
int Div( int m ){
int tmp,ret=1;
if( m<100000 && a[m]==0 )
return 2;
for( int i=0; prime[i]*prime[i]<=m && i<cnt; i++ ){
if( m % prime[i] == 0 ){
tmp = 0;
while( m % prime[i] == 0 ){
tmp ++;
m /= prime[i];
}
ret = ret * ( tmp+1 );
}
}
if( m != 1 )
ret = ret * 2;
return ret;
}
int main( ){
int m, n;
int max, ret;
Initprime( );
while( scanf( "%d%d", &m, &n ) != EOF ){
max = 1;
for( int i=m; i<=n; i++ ){
ret = Div( i );
if( ret > max )
max = ret;
}
printf( "%d\n", max );
}
return 0;
}