【搜尋】【cogs 193】最多因子數
阿新 • • 發佈:2019-01-04
193. 最多因子數
★★★ 輸入檔案:divisors.in 輸出檔案:divisors.out 簡單對比
時間限制:3 s 記憶體限制:128 MB
【問題描述】
數學家們喜歡各種型別的有奇怪特性的數。例如,他們認為945是一個有趣的數,因為它是第一個所有約數之和大於本身的奇數。
為了幫助他們尋找有趣的數,你將寫一個程式掃描一定範圍內的數,並確定在此範圍內約數個數最多的那個數。不幸的是,這個數和給定的範圍的都比較大,用簡單的方法尋找可能需要較多的執行時間。所以請確定你的演算法能在幾秒內完成最大範圍內的掃描。
【輸入格式】
只有一行,給出掃描的範圍,由下界L和上界U確定,滿足2≤L≤U≤1 000 000 000。
【輸出格式】
對於給定的範圍,輸出該範圍內約數個數D最多的數P。若有多個,則輸出最小的那個。
請輸出“Between L and U,P has a maximum of D divisors.”,其中L,U,P和D的含義同前
面所述。
【輸入輸出樣例】
divisors.in
1000 2000
divisors.out
Between 1000 and 2000,1680 has a maximum of 40 divisors.
題解:
我們要對一段區間進行查詢,很明顯並不能一個一個去驗證,時間會炸的飛起。
所以我們考慮對於一個數,它的約數個數是什麼?
如果我們把一個數X分解質因數——>
通過乘法原理我們可以發現,它的約數個數是
於是我們可以從質因數來下手,因為它的範圍是根號n的,然後對於每個質數進行擴充套件就好了。
網上有不錯的文章,說的很詳細,這裡就不多說了,可以戳這裡——>對沒錯就是這裡
Code:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 100001
using namespace std;
int num=0,ans=0,minn,anx,yes[N],no[N];
void xs(){
memset(yes,0,sizeof(yes));
memset(no,0,sizeof(no));
no[0]=no[1]=1;
for (int i=2; i<N; i++){
if (!no[i]) yes[num++]=i;
for (int j=0; j<num && i*yes[j]<N; j++){
no[i*yes[j]]=1;
if (!(i%yes[j])) break;
}
}
}
void work(int start,int s,int x,int L,int R){
if (x>=minn){
if ((s>ans) || (s==ans && x<anx))
ans=s,anx=x;
}
if ((L==R) && (L>x))
work(start,s<<1,x*L,1,1);
for (int i=start; i<num; i++){
if (yes[i]>R) return;
int j=yes[i],ll=L-1,l=L,r=R,y=x,ss=s,m=1;
while (1){
m++; ss+=s; ll/=j; l/=j; r/=j;
if (ll==r) break; y*=j;
work(i+1,ss,y,l,r);
}
m=1<<m;
if (s<(ans/m)) return;
}
}
int main(){
int l,r;
scanf("%d%d",&l,&r);
xs();
if (l==1 && r==1) ans=1,anx=1;
else {
minn=l,ans=2,anx=l;
work(0,1,1,l,r);
}
printf("Between %d and %d, %d has a maximum of %d divisors.\n",l,r,anx,ans);
return 0;
}