回 帖 发 新 帖 刷新版面

主题:第38次编程比赛第一题题目

在N以内(小于等于N)找出一个数,要求:
   1.这个数的约数的个数达到最大,
   2.如果有好几个数满足条件1,仅取最小的那个数

说明:
 1) 1<N<=[color=FF0000]2^32-1[/color],每个N的时限是1000ms。内存限制256M,注意使用适当数据类型,以免溢出。

函数原型:
// n: 范围
// result:结果,存放符合条件的那个数
// count:存入存放符合条件的那个数的约数的个数
// arr:存放那个数的所有约数,按照从小到大的顺序
void Search(unsigned long n, unsigned long *result,int *count,unsigned long arr[]);

例:
n=100, 则 result=60,
在100以内,60和90的约数个数同为12个,达到这个范围内所有整数中,其约数个数的最大值,但60比90小,所有正确答案为60。60共有12个约数:1,2,3,4,5,6,10.12.15.20.30,60.所以count应该存入12,从arr[0]开始,应该依次写入1,2,3,4,5,6,10.12.15.20.30,60。

回复列表 (共47个回复)

21 楼

刚才想了一下,借鉴筛选法求素数,写了一个筛选法和除法相结合的,时间复杂度应该好一点.但似乎不明显,在我的SP2800+上,一百万两个程序都用10S......
How disappointed!
楼主,一人发两个没有问题吧??

//file: MostSubmultiple(筛选法).c
//compiler: VC++ 6.0
#include "stdio.h"
#include "math.h"
#include "stdlib.h"
#include "string.h"
/*
搜索一个数n的约数的基本思路:
类似于求素数时用的筛选法.这种方法在n较大时时间复杂度较单纯的除法算法有一定优势
1.用一块内存作筛选用,内存大小为 n 的 平方根SquareBoot + 1 个字节(用sqrt求平方根时是向下取整)
    ,初始赋值2 ,表示需要检验,尚未确定.
2.然后从 m = 1
    一.如果m能被n整除(即m是其约数),则将第(m + 1)个字节(第一个内存字节没有用到)赋 1 ,
        表示是约数,同时Num/i也是其约数,计数器加2
    二.如果m不能被n整除(不是其约数),则 2m 3m 4m..至SquareBoot. 都不是n的约数,把它们对应的内存
        都赋 0(表示不是约数)
3.m不断加1,直到SquareBoot
4.最后必须单独检验SquareBoot.     由于求Num的平方根SquareBoot时sqrt函数是向下取整的,所以如果SquareBoot恰好
    是n的平方根,则只能算一个.如果不是而只是Num的一个约数,那么n / SquareBoot也是
    就多了两个约数
*/

//数据类型采用unsigned long int
typedef unsigned long int ULI;

void Search(ULI n, ULI *pResult,ULI *pCount,ULI arr[]);

ULI Submultiple(ULI Num);//求出一个数的约数个数,采用筛选法
void Store(ULI Num, ULI TotalSubmultiple,ULI arr[]);//将符合条件的那个数的约数列举出来,存储在arr[]

//由于是搜索n范围内约数个数最多的数,所有整个过程只分配一次内存.(n + 1个字节)
char *pMemory = NULL;

#define        true        1//是约数
#define        false        0//不是约数
#define        Undetermined    2//未确定,需要作除法

#define MaxResult 1000000
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
void main()
{
    ULI i, Count, Result;
    ULI *pArr = NULL;
    ULI n = 1000000;
    ULI SquareBoot = (ULI)sqrt(n);
    /*
    for (i=2; i<=15; i++){
        Count = Submultiple(i);
        printf("%u 有 %u个约数 \n", i, Count);
    }
    */

    pMemory = (char *)malloc(SquareBoot + 2);
    pArr = (ULI*)malloc(MaxResult);//用来存放那个数的所有约数,按照从小到大的顺序
    Search(n, &Result, &Count, pArr);

    printf("%u以内约数最多且最小的数是 %u ,共有 %u 个约数,分别是: \n", n, Result, Count);

    for (i = 0; i < Count; i++){
        printf("%u ",*(pArr +i));
    }    

    free(pArr);    pArr = NULL;
    free(pMemory);    pMemory = NULL;
    getch();
}

22 楼

//接上面的:
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
void Search(ULI n, ULI *pResult,ULI *pCount,ULI arr[])
{
    ULI i;
    ULI MostSubmultiple = 1, Count;
    ULI Result;

    //for (i = 2; i <= n; i++){
    //    
    //}
    //实际上,如果n大于2,则在n范围内约数个数最多的数中最小的一定是偶数.
    for (i = 2; i <= n; i += 2){
        Count = Submultiple(i);
        if (Count > MostSubmultiple){
            MostSubmultiple = Count;
            Result = i;
        }
    }

    Store(Result, MostSubmultiple, arr);
    *pResult = Result;
    *pCount = MostSubmultiple;
}
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
//求出一个数的约数个数
ULI Submultiple(ULI Num)
{
    ULI Count;//约数的个数,最后要将1加入去
    ULI i;
    ULI SquareBoot = (ULI)sqrt(Num);
    char *pTemp;
    char *pEnd = pMemory + SquareBoot;

    memset(pMemory, Undetermined, SquareBoot + 1);
    Count = 0;
    for (i = 1; i< SquareBoot; i++){
        pTemp = pMemory + i;
        if ( *pTemp == Undetermined){
            //一.如果i能被Num整除(即m是其约数),则将第m个字节赋 true,表示是约数,
            //同时Num/i也是其约数,计数器加2
            if (Num % i == 0){
                *pTemp = true;
                Count += 2;
            }
            //二.如果i不能被n整除(不是其约数),则 2i 3i 4i....都不是Num的约数,
            //把它们对应的内存都赋 false(表示不是约数)
            else{
                for (; pTemp <= pEnd; pTemp += i){
                    *pTemp = false;
                }
            }
            //实际上true 或 false都一样,程序只检查 i是否已确定了.
        }
    }

    //如果Mid恰好真是Num的平方根(前面用sqrt函数是向下取整的)
    if (SquareBoot * SquareBoot == Num){
        Count++;    //这里不能像前面一样乘2了,不然就多出了一个
    }
    else if (Num % SquareBoot == 0){//如果只是它的一个约数
        Count += 2;    //Num / Mid也是它的一个约数
    }
    
    return Count;
}
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
//将符合条件的那个数的约数列举出来,存储在arr[]
//参数1: 符合条件的那个数 2.其约数的个数(以便定位) 3.要存储的数组地址
void Store(ULI Num, ULI TotalSubmultiple,ULI arr[])
{
    ULI i, r, Count;    
    ULI SquareBoot = (ULI)sqrt(Num);//搜索到Num的平方根为止
    char *pTemp;
    char *pEnd = pMemory + SquareBoot;

    memset(pMemory, Undetermined, SquareBoot + 1);
    Count = 0;
    //从 arr[0]存储到 arr[--TotalSubmultiple]
    for (i = 1; i< SquareBoot; i++){
        pTemp = pMemory + i;
        if ( *pTemp == Undetermined){
            if (Num % i == 0){
                *pTemp = true;
                arr[Count++] = i;
                arr[--TotalSubmultiple] = Num / i;                
            }
            else{
                for (; pTemp <= pEnd; pTemp += i){
                    *pTemp = false;
                }
            }
            //实际上true 或 false都一样,程序只检查 i是否已确定了.
        }
    }

    //如果Mid恰好真是Num的平方根(前面用sqrt函数是向下取整的)
    if (SquareBoot * SquareBoot == Num){
        arr[Count++] = SquareBoot;
    }
    else if (Num % SquareBoot == 0){//如果只是它的一个约数
        arr[Count++] = SquareBoot;    //Num / Mid也是它的一个约数
        arr[--TotalSubmultiple] = Num / SquareBoot;
    }
    
}

23 楼

#include <iostream>
#include <ctime>
using namespace std;

typedef unsigned long Int;
void getDivisors(Int n, Int* res);

void main()
{
    cout<<"请输入一个自然数:";
    Int number = 2;//范围
    Int result[2] ={1,1};// result:结果result[1]存放符合条件的数,result[0]约数的个数
    Int* pArr = new Int[1000];// arr:存放结果的所有约数,按照从小到大的顺序
    cin>> number;
    

    time_t t = clock();
    for(Int i = 2; i<= number; i++)
    {
        unsigned totalDivisors = 0;
        for(unsigned j = 1; j*j <= i; j++)
        {
            if(i%j==0)
            {
                if( j*j == i)
                    totalDivisors++;
                else
                    totalDivisors += 2;
            }//if
        }//for

        if(  totalDivisors > result[0] )
        {
            result[0] = totalDivisors; 
            result[1] = i;
        }//if
    }//for
    getDivisors(result[1], pArr);



    cout<<number<<"以内约数最多的数是:"<<result[1]<<",其约数个数为:"<<result[0]<<"个,约数如下:";

    cout<<"(本次计算共耗时"<<(clock()-t)*1000/CLK_TCK<<"ms)\n"<<endl;

    for(int i = 0; i< result[0]; i++)
        cout<<pArr[i]<<",";
    cout<<endl;

    delete[] pArr;

    system("pause");
}

void getDivisors(Int n, Int* res)
{
    for(Int i = 1; i<= n; i++)
    {
        if(n%i==0)
            *res++ = i;
    }

    return;
}

24 楼

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#define N 1000
void Search(unsigned long n, unsigned long *result,int *count,unsigned long *arr)
{
    unsigned long i,j;
    int m;
       arr=malloc(sizeof(*arr)*N);
       if(arr==NULL)
       {
           return ;
       }
       result=malloc(sizeof(*result));
       if(result==NULL)
       {
           return ;
       }
       count=malloc(sizeof(*count));
       if(count==NULL)
       {
           return ;
       }
       *result=1;
       *count=0;
       
    for(i=3;i<n;i++)
    {
        m=0;
        for(j=1;j<i/2;i++)
        { 
            
            if(i%j==0)
            {
                m++;
            }
        }
        if(*count<m)
        {
            *count=m;
            *result=i;
        }
    }
    j=0;
    for(i=1;i<(*result)/2;i++)
    {
        if(*result%i==0)
        {
            arr[j]=i;
            j++;
        }
    }
    arr[j]=*result;
}

main()
{  int i;
   unsigned long n;
   unsigned long *result;
   int *count;
   unsigned long *arr;
   Search(1000,result,count,arr);
   printf("%d",*result);
   printf("%d",*count);
   for(i=0;i<*count;i++)
   {
       printf("%d",arr[i]);
   }
   free(arr);
   free(result);
   free(count);
}

25 楼

#include <stdio.h>
#define size 100

void Search(unsigned long n, unsigned long *result,int *count,unsigned long arr[])
{
    int i,j,maxcount;
    
    maxcount=0;
    
    for(i=n;i>=1;i--)
    {
        *count=0;
        for(j=1;j<=i;j++)
        {
            if(i%j==0) (*count)++;
            if(*count>=maxcount)
            {
                *result=i;
                maxcount=*count;
            }    
        }    
    }//end for
    j=0;
    *count=maxcount;
    for(i=1;i<=*result;i++)
    {
        if(*result%i==0) arr[j++]=i;
    }
}     

int main(int argc, char *argv[])
{   
    unsigned long n;
    unsigned long result;
    unsigned long arr[size];
    int count=0;
    int i;
    
    scanf("%ld",&n);
    Search(n,&result,&count,arr);
    printf("要求数:%ld\n",result);
    for(i=0;i<count;i++)
    {
        printf("%ld ",arr[i]);
    }        
    printf("\n");
    system("PAUSE");    
    return 0;
}

26 楼

唉,网吧里TC用不了,希望程序没有错啊![em10][em10][em10][em10][em10]

#include<stdio.h>

void Search(unsigned long n,unsigned long *result,int *count ,unsigned long *arr);

int main()
{
   unsigned long n,result,arr[200]={0};
   int count,i;
   while(1)
   {
       scanf("%lu",&n);
       if(n==0)
          break;
       Search(n,&result,&count ,arr);
       printf("\nFor : %lu\n\n",n);
       printf("The result is %lu,the count is %d\n",result,count);
       for(i=0;i<count;++i)
          printf("%lu ",arr[i]);
   }

   system("pause");
   return 0;
}



void Search(unsigned long n,unsigned long *result,int *count ,unsigned long *arr)
{

   unsigned long b,i,resultTemp;
   int counterTemp,j;

   *count=0;
   for(b=n/4*2;b<=n;b+=2)
   {
      counterTemp=0;
      for(i=1;i*i<=b;++i)
      {
         if(b%i==0)
         {
            if(i*i==b)
               ++counterTemp;
            else
               counterTemp+=2;
         }
      }

      if(counterTemp>*count)
      {
         *result=b;
         *count=counterTemp;
      }
   }
   
   for(j=0,i=1;i*i<=(*result);++i)
      if((*result)%i==0)
          arr[j++]=i;
   if(*count%2!=0)
      counterTemp=j-2;
   else
      counterTemp=j-1;
   for( ;counterTemp>=0;--counterTemp)
      arr[j++]=(*result)/arr[counterTemp];
}

27 楼

#include<iostream.h>

void main()
{
    long n=0,m=0;
    cout<<"请输入范围的上限:";
    cin>>n;
    int a=0,b=0;
    for(int j=1;j<=n;j++)
    {
        a=1;
        for(int k=1;k<=j/2;k++)
        {
            if(j%k==0) a++;
        }
        if(a>b){b=a;m=j;}
    }
    cout<<"所求的数为: "<<m<<",其约数个数为:"<<b<<endl;
}

28 楼

/*大于2亿就超时了*/
#define   MAXSIZE    9
unsigned long  prime[MAXSIZE+1] = {
2,3,5,7,11,13,17,19,23,29};
inline void Find(unsigned long n,unsigned long *r,int *c)
{
    int i,j,k,step,start,count,ti,tc,tr;
    
    start = step = 2;
    tr  = count = 1;
    if(n >= 100){
         step = 60;
        //start = 60;
         start = (n/2/step +1)*step;
    }    
    for(i = start; i <= n; i += step){ 
        for(j = 0,tc = 1,ti = i;prime[j] <= ti && j <= MAXSIZE; j++){
            for( k = 1; ti%prime[j] == 0; k++){
                ti /= prime[j];
            }
            tc *= k;
        } 
        if(tc > count){
             count = tc;
             tr =  i;
        }
    }
    *c = count;
    *r = tr;
}
inline void Fill(unsigned long a[],unsigned long rr, int cc)
{
    int i;
    unsigned long j,temp;
    a[0] = 1;
    for(i = 0,j = 1,temp = rr; j < temp; j++){ 
        if(rr%j == 0){
            a[i++] = j;
            temp = rr/j; 
            a[--cc] = temp;           
        }
    }  
}
void Search(unsigned long n, unsigned long *result,int *count,unsigned long arr[])

    Find(n,result,count); 
    Fill(arr,*result,*count);
}

29 楼

环境vc++ 6.0  内存512MB

#include <stdio.h>

void main()

{  
 int count = 0, m, n, i, j, result, arr[1000];
   
 scanf("%d", &n);
   
 for (result = n, m = n / 2; n > m; n--)

 {    if (n % 2 == 0)         
        
        {   for (i = 1, j = 0; i <= n; i++)
                
                if (n % i == 0) 
                
                {    
                    j++;
                }
            
            if (j >= count && n <= result)
            
            {    
                 count = j; 
                 
                 result = n;
            }
        
        }
        
 }
 
 for (i = 1, j = 0; i <= result; i++)
     
     if (result % i == 0)
     
     {   
         arr[j] = i;
     
         j++;
     }
 
 printf("\nresult = %d ; \ncount = %d ; \narr[%d] = ", result, count, count);
 
 for (i = 0; i < count; i++)
 
     printf("%d  ", arr[i]);
 
 printf("; \n");
 
}

30 楼

const int prime[8]={2,3,5,7,11,13,17,19};

void Try(int step,double n,int* exp,double* max,int *maxCount,int* maxExp)
{
    unsigned i,p=1;
    for (i=0;(step==0 || i<=exp[step-1]) && p*prime[step]<=n && i<8;i++)
    {
        p*=prime[step];
        exp[step]=i+1;
        if (step+1<8) Try(step+1,n/p,exp,max,maxCount,maxExp);
    }
    if (i==0)
    {
        int count=1;
        for (i=0;i<step;i++)
            count*=(exp[i]+1);
        if (count>*maxCount || (count==*maxCount && *max<n))
        {
            *maxCount=count;
            *max=n;
            memset(maxExp,0,sizeof(int)*8);
            memcpy(maxExp,exp,sizeof(int)*step);
        }
    }
}

void Try2(int* exp,const int* prime,unsigned long* arr,int* pArr,unsigned long t=1)
{
    unsigned long i;
    for (i=0;i<=*exp;i++)
    {
        if (*(exp+1)) Try2(exp+1,prime+1,arr,pArr,t);
        else 
        {
            arr[*pArr]=t;
            (*pArr)++;
        }
        t*=*prime;
    }
}

int cp(const void* a,const void* b)
{
    return *((unsigned long*)a) > *((unsigned long*)b) ? 1 :-1;
}

void Search(unsigned long n, unsigned long *result,int *count,unsigned long arr[])
{
    int exp[8]={0},maxExp[8];
    double m=0;
    int i,j;
    *count=*result=1;

    Try(0,n,exp,&m,count,maxExp);

    for (i=0;i<8;i++)
        for (j=0;j<maxExp[i];j++)
            (*result)*=prime[i];

    int pArr=0;
    Try2(maxExp,prime,arr,&pArr);
    qsort(arr,*count,sizeof(unsigned long),cp);
}

我来回复

您尚未登录,请登录后再回复。点此登录或注册