南邮 OJ 1203 最多约数问题

来源:互联网 发布:spring 源码书籍 编辑:程序博客网 时间:2024/06/18 17:35

最多约数问题

时间限制(普通/Java) : 20000 MS/ 30000 MS          运行内存限制 : 81920 KByte
总提交 : 483            测试通过 : 61 

比赛描述

   正整数x的约数是能整除x的正整数。正整数x的约数个数记为divx)。例如,1,2,5,10都是正整数10的约数,且div(10)=4 对于给定的2个正整数a<=b,编程计算ab之间约数个数最多的数。

输入

输入的第1行有两个正整数ab

输出

若找到的a和b之间约数个数最多的数是x,则输出div(x)。

样例输入

1 36

样例输出

9

题目来源

算法设计与实验题解



//设正整数x的质因子分解为 x=p1^N1*p2^N2...pn^Nn//则div = (N1+1)(N2+1)...(Nn+1)#include<stdio.h>#define MAX_P 10000//最大的质数#define P_NUM 1229//质数的个数int prime[P_NUM+1];//存放素数int prime_num;//素数的总个数int max_num;//最多约数的个数int numb;//有着最多约数的个数void get_primes(){bool is_prime[MAX_P+1];int i,j;for(i=2;i<=MAX_P;++i){is_prime[i] = 1;}for(i=2;i<=MAX_P;++i){if(is_prime[i]){for(j=i<<1;j<=MAX_P;j+=i){is_prime[j] = 0;}}}for(i=2,j=0;i<=MAX_P;++i){if(is_prime[i]){prime[++j] = i;}}prime_num = j;}//from  :第几个质数//total :当前约数最多个数//number:为当前搜索到的数,total是指number中包含的因子数//low   :区间下限//up    :区间上限void search(int from,int total,int number,int low,int up){if(number>=1){//约数个数最多的数if ((total>max_num) || ((total==max_num) && (number<numb)) ){max_num = total;//约数最多个数numb = number;//约数最多的数,约数个数相同时,记录更大的数}}if((low==up) && (low>number)){//区间中只有一个数,且大于当前约数最多的数search(from,total*2,number*low,1,1);// ?}for(int i=from; i<=prime_num; i++){//对质数进行枚举if(prime[i]>up){//质数大于上届,返回return;}else{int cur_prime=prime[i];//当前素数int div_low=low-1;//区间左端点-1int div_up=up;//区间右端点int cur_num=number;//当前约数最多的数int count=total;//约数计数int m=1;while (true){m++;count += total;div_low /= cur_prime;div_up /= cur_prime;if(div_low == div_up){break;//合法性剪枝,以当前状态搜索下去,结果肯定不在区间内了,可剪去}//不过,这一剪枝作用不是很大,因为即使不剪,再搜索一层也就退出了cur_num *= cur_prime;search(i+1, count, cur_num, div_low+1, div_up);//深度优先,搜索下一级?}m = 1<<m;if (total < max_num/m){//当前所能取到的(理想情况)最大约数个数就是total*2^q。return;//如果这个数仍然无法超过当前最优解,则这一分支不可能产生最优解,可以剪去}}}}int main(){get_primes();int a,b;scanf("%d%d",&a,&b);if(a==1 && b==1){return 1;}else{max_num=2;search(1,1,1,a,b);//从第一个质数开始搜索,当前约数最多个数为1,当前约数最多的数为1}//区间为[a,b]printf("%d\n",max_num);}






0 0