1. 程式人生 > >【搜尋】【cogs 193】最多因子數

【搜尋】【cogs 193】最多因子數

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分解質因數——>

X=2m13m25m3...nmk
通過乘法原理我們可以發現,它的約數個數是
(m1+1)(m2+1)(m3+1)...(mk+1)
於是我們可以從質因數來下手,因為它的範圍是根號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; }