1. 程式人生 > >最多的約數(divisor)

最多的約數(divisor)

題目簡述:

求1~N 的數中因子是最多的數

Sample Input
100
Sample Output
60
Data Constraint
Hint
有30%的資料,n不超過1000。
有50%的資料,n不超過1000000。
有100%的資料,1 ≤ n ≤ 10^16

The Solution

我們很容易想到暴力,但毋庸置疑這是超時的。。

so go on…

Algorithm1:

我們可以知道,計算約數的個數和質因數分解有著很大的聯絡:

若Q的質因數分解為:Q=p1k1p2k2pmkmp1pmk1km1Q(k1+1)(k2+1)(km+1)

但是質因數分解的時間複雜度很高,所以也會超時。

Algorithm2

通過以上的公式,我們可以“突發奇想”:為何不能把質因數分解的過程反過來呢?

這個演算法就是列舉每一個素數。
初始時讓m=1,然後從最小的素數2開始列舉,
列舉因子中包含0個2、1個2、2個2…k個2,直至m2k大於區間的上限N。
在這個基礎上列舉3、5、7……的情況,算出現在已經得到的m的約數個數,
同時與原有的記錄進行比較和替換。直至所有的情況都被判定過了。

這個演算法的優化:
如果p1p2p3pk>N(pi表示第i個素數),那麼只要列舉到p k-1,既不浪費時間,也不會遺漏。

根據以上的演算法,對於上限需要列舉436555171個數,也會超時,不過可以過70-80%的資料。

Algorithm3

以上的演算法還不是最好的,還可以繼續優化。

我們看以下的例子:

6=23
10=25

6和10的質因數分解“模式”完全相同,所以它們的約數個數是相同的。
但是由於3<5,所以6<10。

12=223
18=322

12和18的質因數分解“模式”完全相同,所以它們的約數個數是相同的。
但是由於12的質因數分解中2的指數大於3的指數,18的質因數分解中3的指數大於2的指數,所以12<18。

根據以上的舉例,我們也可以對Algorithm2中的演算法進行一個改進:
可以在列舉時進行一個優化,使得列舉到的數字中2的指數不小於3的指數


3的指數不小於5的指數……這樣我們就能夠得到質因數分解“模式”相同的最小數(證明略)。
再對於每一個得到的數進行比較和記錄。這個演算法對於上限只需要列舉34136個數,幾乎達到了極限。

CODE

#include <cstdio>
#include <iostream>
#include <algorithm>
#define fo(i,a,b) for (int i=a;i<=b;i++)
using namespace std;

typedef long long ll;

int Prime[20];
bool bz[20];

ll n,Max,Num;

inline void Sieve()//線篩。。其實並無卵用。。20而已暴力綽綽有餘,若問我為何。。裝逼嘿嘿嘿
{
    fill(bz,bz+1+20,true);
    fo(i,2,20)
        if (bz[i])
        {
            ll j = i +i;
            while (j <= 20) bz[j] = false,j += i;   
        }       
    ll ii ,j;
    for (ii = 2,j = 0;ii <= 20 ;ii ++)
        if (bz[ii]) Prime[++ j] = ii;
}

void Search(ll number,int w,int tot,int p) /*分別代表:當前的數,當前質數,約數的個數,指數限制*/
{
    if (tot > Max || (tot == Max && number < Num)) Max = tot,Num = number;
    int j = 0, l = 1,q;
    long long i = number;
    while (j < p)
    {
        j++;l++;
        if (n / i < Prime[w]) break;
        q = tot * l;
        i = i * Prime[w];
        if (i <= n) Search(i,w + 1,q,j);//為什麼是 j,為了是 前一個素數的指數大於後一個素數的指數
    }
}
int main()
{
    Sieve();
    scanf("%lld",&n);
    Search(1,1,1,30);
    printf("%lld\n",Num);
    return 0;
}

相關推薦

1-3:約數問題

最多約數問題。正整數x 的約數是能整除x的正整數,其約數的個數記為div(x),例如div(10)=4。設a 和b 是兩個正整數,找出a 和b 之間約數個數最多的數x 的約數個數。     樣例輸入:   1 36 樣例輸出:  

約數相關問題

申明:思路參考該blog 吐槽:上古時期的資料時真的有毒,注意有一個點錯了;網上各路神仙的解法有點不靠譜,各種暴力加上玄學的騙分(姑且是吧,欺負資料水)都能過也是服了。於是自己上網慢慢找了一下,正確解法。 由於資料較水,演算法方面可能會有些

【演算法】約數問題

最多約數問題 題目描述 正整數x的約數是能整除x的正整數。正整數x的約數個數記為div(x)。例如,1,2,5,10都是正整數10的約數,且div(10)=4。 對於給定的2個正整數a<=b,程式設計計算a與b之間約數個數最多的數。 輸入 輸入的第1行有兩個正整數a和

約數問題

問題 最多約數問題:正整數x的約數是能整除x的正整數。正整數x 的約數個數記為div(x)。例如,1,2,5,10 都是正整數10 的約數,且div(10)=4。設a 和b 是2 個正整數,a≤b,找出a和b之間約數個數最多的數x及其最多約數個數。 方法

計算機演算法設計與分析課本(王曉東著)課後演算法實現題1-3 約數問題

問題描述: 正整數x的約數是能整除x的正整數。正整數x的約數個數記為div(x)。例如,1 2 5 10都是10的約數,且div(10)=4。設a和b是2個正整數,a<=b,找出a和b之間約數個數最多的數x。 演算法設計: 對於給定的2個正整數a<=b,計算a和b之間約數個數最多

約數(divisor)

題目簡述: 求1~N 的數中因子是最多的數 Sample Input 100 Sample Output 60 Data Constraint Hint 有30%的資料,n不超過1000。 有50%的資料,n不超過1000000。 有100

小公倍數/大公約數高效演算法模板)

最小公倍數和最大公約數            兩數最小公倍數    輾轉相除法求最大公約數,使a>b,a,b不斷取餘數直到a,b相等 int gcd(int a, int b) { if(a < b) a = a^b, b = b^a, a = a^

大公約數小公倍數(Greatest Common Divisor and Least Common Multiple)

定義: 最大公約數(英語:greatest common divisor,gcd)。是數學詞彙,指能夠整除多個整數的最大正整數。而多個整數不能都為零。例如8和12的最大公因數為4。 最小公倍數是數論中的一個概念。若有一個數$$X$$,可以被另外兩個數$$A$$、$$B$$整除,且$$X$$大於(或等於)$

學以致用——Java原始碼——大公約數計算的普通演算法與歐幾里得演算法的比較(Greatest Common Divisor

Our life is frittered away by detail ... Simplify, simplify. by Henry Thoreau (美國哲學家亨利·梭羅說,我們的生活被瑣碎的細節消磨殆盡,要簡化,要簡化!) 所以,如果能夠找到現成的解決方案,我們就沒必要自己

計算大公約數 GCD (Greatest Common Divisor)和小公倍數 LCM (Least Common Multiple)

文章目錄 最大公約數GCD 也叫做Greatest Common Factor (最大公因數). 以下是Java code,說成C++也沒差。 from Introduction to Java Programming and stackoverflow: 1

大公約數小公倍數

描述 出現 mage 最大公約數 images code ger return ges 一、問題描述 從鍵盤輸入兩個正整數a和b,求其最大公約數和最小公倍數。 二、算法思想及代碼 求最小公倍數算法:最小公倍數=兩整數的乘積÷最大公約數 求最大公約數算法: (1)輾轉相除法

數組中出現的數,以及接口 Map.Entry<K,V>

int try tools pub length rem value contains span 1 package test.tools; 2 3 import java.util.Collection; 4 import java.util.Collecti

nginx rewrite正則子組匹配到$9

spl html splay erb ice line display and 需要 nginx rewrite正則匹配()匹配子組最多匹配到$9,就是從$0到$9 當需要匹配更多子組時,可通過變量來實現 if ($uri ~ ^/forum-15/sortid-74/(.

尋找出現次數的id

exti 出現 出現次數 util nbsp for pack 次數 題目 題目要求: 論壇中有一個id評論過於頻繁,其出現次數占到3/4,如今簡單編程尋找此id。 設計思想:

【51NOD-0】1011 大公約數GCD

style lose gif lap blog %d 51nod ret display 【算法】歐幾裏德算法 #include<cstdio> int gcd(int a,int b) {return b==0?a:gcd(b,a%b);} int mai

oj-ccf-csp-201312-1-出現次數的數

str nbsp index name std print space {} include #include<cstdio> #include<algorithm> using namespace std; const int maxn

求數組中反復次數的元素

down add 時間復雜度 空間 append 鍵值對 Language trac mod 1.問題描寫敘述   比如:數組a={2,3,1,5,5,5,5,7,8,1}。元素2、3、7、8各出現1次。1出現兩次。5出現4次,則反復次數最多的元素為5

求一個字符串中連續出現次數的子串

article 規律 生成 clu 一次 strong tor first sub 題目:求一個字符串中連續出現的次數最多的子串。 例如,字符串“abababc”,最多連續出現的為ab,連續出現三次。 思路: 例如字符串“abababc”,最多連續出現的為ab,連續出現

40.@返回字符串中出現次數的那個字符和次數2

script 最大 spl 技術分享 char 獲取 code java log 1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4 <meta charset="U

輾轉相除求大公約數小公倍數

scanf ret include %d 溢出 main sca 約數 stdio.h #include<stdio.h> int gcd(int a,int b) { if(b!=0) gcd(b,a%b); else return a; } int