5

There was 10th question in project eular.

The problem is to find the sum of all prime numbers not greater than N.

My soln for the problem is :

int solve(int n){

    bool check[n+1];
    for(int i=0;i<=n;i++){
        check[i]=true;
    }

    for(int i=2;i*i<=n;i++){
        if(check[i]){
            for(int j=i*i;j<=n;j+=i){
                check[j]=false;
            }
        }
    }

    int sum=0;
    for(int i=2;i<=n;i++){
        if(check[i]){
            sum+=i;
        }
    }
    return sum;
}

Still the problem was not optimized enough as i was getting ' termination due to timeout ' message.

How can i optimize this code better.

The constraints are :

1<= T <= 10^4 ( T is no. of test cases )

1<= N <= 10^6

You can try it yourself here

Arty
  • 14,883
  • 6
  • 36
  • 69
  • 2
    You only need to run the sieve once, up to 10^6 at the start of the first problem. Then you can use it for all the other test cases without recalculating. Also check how large the answer is going to be. Should `sum` be a long? – rossum Jan 09 '22 at 16:34
  • A few hints: 1) determine max n value and store all primes up to this value 2) calculate al sums up to max n in a single pass 3) use long variables for the sum – Rocco Jan 09 '22 at 17:37
  • Read about Sieve of Eratosthenes to find Prime Numbers quickly, then read about how to preprocess sum using Prefix Sum array. – Praveen Ojha Jan 09 '22 at 18:35
  • You can also use the sieve for the numbers below `sqrt(n)`. You can accelerate your double for loop a lot by it. – Sebastian Jan 09 '22 at 19:41
  • There are "only" 78,498 primes under 10^6. You can just have a precalculated table, which will fit in less than half a megabyte. – Raymond Chen Jan 17 '22 at 17:07

2 Answers2

0

You have T up to 10^4 (number of tests), and for each of them you run your solve() from start.

Just run solve() one time for maximal possible n and save results of check and sums array into global variables, to reuse them later. Then on each test case just return sums[n].

Also don't forget that sum of primes less than maximal N (1 million) is equal to 37550402023, which overflows maximal possible int value, so you have to use 64-bit int64_t instead for sums.

Below is your code with minimal fixups needed to make it very fast, according to my suggestions above:

Try it online!

#include <cstdint>
#include <iostream>

enum { max_n = 1000000 };
bool check[max_n+1] = {};
int64_t sums[max_n+1] = {};

void solve() {
    for(int i=0;i<=max_n;i++){
        check[i]=true;
    }

    for(int i=2;i*i<=max_n;i++){
        if(check[i]){
            for(int j=i*i;j<=max_n;j+=i){
                check[j]=false;
            }
        }
    }

    int64_t sum=0;
    for(int i=2;i<=max_n;i++){
        if(check[i]){
            sum+=i;
        }
        sums[i] = sum;
    }
}

int main() {
    solve();

    int ntests = 0;
    std::cin >> ntests;
    for (int i = 0; i < ntests; ++i) {
        int n = 0;
        std::cin >> n;
        std::cout << sums[n] << std::endl;
    }    
}

Input:

6
10
100
1000
10000
100000
1000000

Output:

17
1060
76127
5736396
454396537
37550402023
Arty
  • 14,883
  • 6
  • 36
  • 69
0
#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
#include <bitset>

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int t;
    std::cin >> t;
    std::vector<int> qn;
    qn.reserve(t);
    int i, tmp, lim = 0;
    for (i = 0; i != t; ++i) {
        std::cin >> tmp;
        qn.emplace_back(tmp);
        lim = std::max(lim, tmp);
    }
    auto primes = std::make_unique<std::bitset<1000000 + 1>>();
    primes->set();
    primes->set(0, false);
    primes->set(1, false);
    int j;
    for (i = 2; i * i <= lim; ++i) {
        if (primes->test(i)) {
            for (j = i * i; j <= lim; j += i) {
                primes->set(j, false);
            }
        }
    }
    std::vector<long long> ans(lim + 1);
    for (i = 2; i <= lim; ++i) {
        ans[i] = ans[i - 1];
        if (primes->test(i)) {
            ans[i] += i;
        }
    }
    for (auto const& q : qn) {
        std::cout << ans[q] << '\n';
    }
    return 0;
}

Read t. Define qn which is the vector that you are going to store your questions in. Use reserve to allocate memory for t element and thus avoid preallocation. Read your questions (tmp), store them in qn and find out which is the greatest of them all (lim). Allocate bitset on the heap via the unique_ptr primes. Run the sieve of Eratosthenes algorithm on primes up to lim. Define the vector ans which is the vector that you are going to store the answers of your questions in. Run the prefix sums algorithm on it that is If the number i is not prime move the sum accumulated so far (ans[i] = ans[i - 1];) otherwise add i to the newly generated sum. Loop through qn and print the answer of each question q.