Лучший способ найти простые множители числа

Я решаю задачу, в которой вам дано несколько тестовых примеров. Для каждого случая вам дается диапазон (от x до y включительно). В пределах этого диапазона я должен посчитать все числа, сумма простых множителей которых точно равна K.

Например:

5 15 2

Мы знаем, что существует 5 чисел, у которых ровно 2 простых делителя (6, 10, 12, 14 и 15).

Теперь мой код работает отлично, но слишком медленно. И я искал более быстрый способ генерации простых чисел с помощью C++. Вот мой код.

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <math.h>
#include <string>
#include <sstream>
#include <vector>
#include <iomanip>
#include <deque>
#include <queue>

#define Fill(s, v) memset(s, v, sizeof(s))
#define skipChar() (scanf("%c", &useless));
#define scan(x) do{while((x=getchar())<'0'); for(x-='0'; '0'<=(_=getchar());x=(x<<3)+(x<<1)+_-'0');}while(0)
#define rekt return false;
#define notrekt return true;
char _, useless;

using namespace std;
typedef pair <int, int> intpair;
vector<int> primes;

void sieve(int n){
bool *prime = new bool[n +1];
fill(prime, prime + n+1, true);
prime[0] = false;
prime[1] = false;
int m = sqrt(n);
for(int i = 2; i <= m; i++)
    if(prime[i])
        for(int k = i*i; k <= n; k+=i){
            prime[k] = false;
            if(prime[k])primes.push_back(k);
        }
for(int i = 0; i <n; i++){
    if(prime[i])
        primes.push_back(i);
     }
}

int main()
{
int t;
int c = 1;
scan(t);
sieve(1000);
while(t--){
    int a, b, k;
    scan(a);
    scan(b);
    scan(k);
    int realCount = 0;
    for(int i = a; i <= b; i++){
        int count = 0;
        for(int j = 0; j < primes.size(); j++){
            if(i % primes[j] == 0){
                    count++;
            }
        }
        if(count == k)realCount++;
    }
    cout << "Case #"<< c << ": "<< realCount <<endl;
    c++;
    }
}

Спасибо за помощь!

Спасибо всем за вклад! Вот быстрый и оптимизированный код!

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <math.h>
#include <string>
#include <sstream>
#include <vector>
#include <iomanip>
#include <deque>
#include <queue>

#define F(a, s, val) fill(a, a + s, val);
#define skipChar() (scanf("%c", &useless));
#define scan(x) do{while((x=getchar())<'0'); for(x-='0'; '0'<=_=getchar());x=(x<<3)+(x<<1)+_-'0');}while(0)
#define rekt return false;
#define notrekt return true;
char _, useless;

using namespace std;
typedef pair <int, int> intpair;

int *omega = new int[10000001];

void omg(){
    for(int i = 2; i < 10000000; i++)
            if(omega[i] == 0)
                    for(int j = i; j < 10000001; j+=i)
                            omega[j]++;
}

int main(){
    int t;
    int c = 1;
    F(omega, 10000001, 0);
    omg();
    scan(t);
    while(t--){
        int a, b, k;
        scan(a);
        scan(b);
        scan(k);
        int cc = 0;
        for(int i = a; i <= b; i++)
                    if(omega[i] == k)
                            cc++;
        printf("Case #%i: %i\n", c, cc);
        c++;
        }
    }

person Boris    schedule 18.01.2015    source источник
comment
Я думаю, вы хотите посчитать все числа, которые имеют K различных простых множителей. не сумма простых множителей. Правильно?   -  person    schedule 19.01.2015
comment
Насколько большим может быть диапазон?   -  person mrk    schedule 19.01.2015
comment
#define убедил меня даже не смотреть на ваш код.   -  person gnasher729    schedule 19.01.2015
comment
спасибо за очень ценное мнение!   -  person Boris    schedule 19.01.2015
comment
@ gnasher729, это, вероятно, шаблон конкурентного программирования.   -  person mrk    schedule 19.01.2015
comment
Поскольку ваш код работает, вы должны опубликовать этот вопрос на [email protected]. Они хороши в оптимизации и проведении проверок кода.   -  person Thomas Matthews    schedule 19.01.2015
comment
Да, я писал о Facebook Hacker Cup 2015.   -  person Boris    schedule 19.01.2015


Ответы (2)


Вы должным образом предварительно вычисляете простые числа в нужном диапазоне с помощью Решета Эратосфена, и это хорошо. Однако то, что вы хотите знать, — это количество различных простых множителей каждого числа в вашем диапазоне, а не то, является ли оно простым или составным.

Этот расчет также может быть выполнен путем просеивания. Вместо хранения массива логических значений сохраните массив целых чисел, которые подсчитывают количество различных простых множителей, и увеличивайте его для каждого простого множителя, найденного во время просеивания.

Просеивание выглядит так; мы называем массив omega, потому что это имя, которое теоретики чисел дают функции, которая возвращает количество различных делителей числа:

omega := makeArray(2..limit, 0)

for i from 2 to limit
    if omega[i] == 0
        for j from i to limit step i
            omega[j] := omega[j] + 1

Первые несколько элементов массива omega: 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 2, 2, 1, 1, 2, 1, 2, 2, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 1, 2, 2, 2, 2, 1, 2, 2‌​, 2, 1, 3 (A001221).

Если у вас есть omega, вы можете использовать его для всех своих запросов:

function f(a, b, c)
    count := 0
    for k from a to b
         if omega[k] == c
             count := count + 1
    return count

Например, f(5,15,2) = 5 (набор 6, 10, 12, 14, 15), f(2,10,1) = 7 (набор 2, 3, 4, 5, 7, 8, 9), f(24,42,3) = 2 (набор 30, 42) и f(2,10000000,7) = 1716.

Если ваш диапазон слишком велик для удобного просеивания, вам придется разложить каждое число в диапазоне и подсчитать те, у которых правильное количество различных факторов.

person user448810    schedule 19.01.2015
comment
Спасибо, это действительно помогло. - person Boris; 19.01.2015

ваша функция сита может быть оптимизирована таким образом.

vector<int> siev(int max) {
    vector<int> ret;
    bool isPrime[max];

    for(int i=2; i<max; i++) isPrime[i]=true; // reset all bits

    for(int i=2; i<max; i++) {
        if(isPrime[i]) {
            ret.push_back(i);
            for(int j=i*i; j<max; j+=i) {
                isPrime[j]=false;
            }
        }
    }

    return ret;
}
person user3064869    schedule 18.01.2015