【问题标题】:Better way of finding Prime Factors of a number找到一个数的质因数的更好方法
【发布时间】:2015-01-18 23:32:32
【问题描述】:

我正在解决一个问题,其中为您提供了许多测试用例。对于每种情况,您都会获得一个范围(从 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++;
        }
    }

【问题讨论】:

  • 我想你想计算所有具有 K 不同素数的数字。不是素数之和。对吗?
  • 范围可以有多大?
  • #defines 说服我甚至不看你的代码。
  • 感谢您的宝贵意见!
  • @gasher729 这可能是一个有竞争力的编程模板。

标签: c++ math primes


【解决方案1】:

您可以使用 Eratosthenes 筛正确地预先计算所需范围内的素数,这很好。但是,您想知道的是您范围内每个数字的不同质因数的数量,而不是它是质数还是合数。

这个计算也可以通过筛分来完成。与其保留一个布尔数组,不如保留一个整数数组,计算不同的素因子的数量,并为筛选过程中找到的每个素因子递增。

筛分是这样的;我们称数组为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

如果您的范围太大而无法方便地筛选,您将不得不考虑范围中的每个数字并计算具有正确数量的不同因子的那些。

【讨论】:

  • 谢谢,这真的很有帮助。
【解决方案2】:

您的筛子功能可能会像这样优化。

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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-21
    • 2013-04-11
    • 2016-03-17
    • 2020-07-29
    • 1970-01-01
    • 1970-01-01
    • 2016-06-20
    • 2019-06-12
    相关资源
    最近更新 更多