主题:第38次编程比赛第一题题目
liangbch [专家分:1270] 发布于 2006-08-18 12:16:00
在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 楼
abcdxjs [专家分:240] 发布于 2006-08-19 16:10:00
刚才想了一下,借鉴筛选法求素数,写了一个筛选法和除法相结合的,时间复杂度应该好一点.但似乎不明显,在我的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 楼
abcdxjs [专家分:240] 发布于 2006-08-19 16:10:00
//接上面的:
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
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 楼
ysol [专家分:10] 发布于 2006-08-19 18:53:00
#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 楼
关浩 [专家分:170] 发布于 2006-08-19 19:05:00
#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 楼
侍鱼 [专家分:80] 发布于 2006-08-19 19:41:00
#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 楼
freeeerf [专家分:5440] 发布于 2006-08-19 21:28:00
唉,网吧里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 楼
qiulihua83 [专家分:0] 发布于 2006-08-19 21:55:00
#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 楼
ccpp [专家分:9360] 发布于 2006-08-19 22:13:00
/*大于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 楼
libo93122 [专家分:130] 发布于 2006-08-19 22:20:00
环境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 楼
neverPE [专家分:1620] 发布于 2006-08-19 23:17:00
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);
}
我来回复