Related
This question already has answers here:
Calculate the factorial of an arbitrarily large number, showing all the digits
(11 answers)
Closed 3 years ago.
I am trying to solve a very simple task about finding nCk when 1<=n,k<=50. I can't seem to find a way of outputting the result for very large numbers like 50 in C++. My algorithm only works for small integer values.
I implemented a factorial function for the nCk formula, but I can't find a way to solve such task for bigger number, and in 1s.
#include <iostream>
using namespace std;
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int i, n, k;
long long res, num, den;
res = num = den = 1;
cin >> n >> k;
if (n < k) {
cout << 0;
return 0;
}
if (n == k || k == 0) {
cout << 1;
return 0;
}
for (i = 1; i <= k; i++) {
if ((n - i + 1) % i == 0) {
res = res * ((n - i + 1) / i);
}
else {
num *= (n - i + 1);
den *= i;
}
}
cout << (res*num)/den;
return 0;
}
This solution requires some mathematics rather than programming (to solve the problem of overflow).
You have:
n! / (k! * (n - k)!)
You can eliminate common factors easily enough by expanding it. For example:
n = 8, k = 3
8*7*6*5*4*3*2*1 / ((3*2*1) * (5*4*3*2*1))
which expands to
8*7*6*5*4*3*2*1 / 3*2*1*5*4*3*2*1
notice how we can remove 5*4*3*2*1 from both by the rules of division? We then get
8*7*6 / 3*2*1
This will be a lot easier to calculate.
Eventually if you keep getting bigger you will run into issues anyways, so you may need to look into Boost's Multiprecision
Your current formula is
binom(n, k) = n! / (n - k)!k!
This formula is OK for mathematics, but not OK for computing. Simplify it:
binom(n, k) = n(n - 1)(n - 2) ... (n - k + 1) / k!
which involves fewer terms. Also note that
binom(n, k) = binom(n, n - k)
which can be used as an optimization if k > n / 2.
Also, if the numbers are too large, you need to use a multi-precision library like GMP.
I'm trying to solve the 2nd problem on Project Euler where I have to print the sum of all even Fibonacci numbers under 4 million. I'm using the following code but the program is not returning any value. When I replace 4000000 by something small like 10, I get the sum. Does that mean my program is taking too long? What am I doing wrong?
#include <iostream>
using namespace std;
int fibonacci(int i) {
if (i == 2)
return 2;
else if (i == 1)
return 1;
else return fibonacci(i - 1) + fibonacci(i - 2);
}
int main() {
int currentTerm, sum = 0;
for (int i = 1; i <= 10; i++) {
currentTerm = fibonacci(i);
if (currentTerm % 2 == 0)
sum += currentTerm;
}
cout << sum;
return 0;
}
Problem 2 of project Euler asks (emphasis mine)
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
Doing
for (int i = 1; i <= 4000000; i++)
{
currentTerm = fibonacci(i);
// ...
}
You are trying to calculate up to the 4,000,000th Fibonacci number, which is a very big beast, while you should stop around the 33th instead.
The other answers already pointed out the inefficiency of the recursive approach, but let me add some numbers to the discussion, using this slightly modified version of your program
#include <iostream>
#include <iomanip>
int k = 0;
// From https://oeis.org/A000045 The fibonacci numbers are defined by the
// recurrence relation F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
// In the project Euler question the sequence starts with 1, 2, 3, 5, ...
// So in the following I'll consider F(1) = 1 and F(2) = 2 as The OP does.
long long fibonacci(long long i)
{
++k;
if (i > 2)
return fibonacci(i - 1) + fibonacci(i - 2);
else
return i;
}
int main()
{
using std::cout;
using std::setw;
const long limit = 4'000'000;
long sum = 0;
cout << " i F(i) sum calls\n"
"-----------------------------------\n";
for (int i = 1; ; ++i)
{
long long F_i = fibonacci(i);
if ( F_i > limit ) // <-- corrected end condition
break;
if (F_i % 2 == 0)
{
sum += F_i;
cout << setw(3) << i << setw(10) << F_i
<< setw(10) << sum << setw(11) << k << '\n';
}
}
cout << "\nThe sum of all even Fibonacci numbers less then "
<< limit << " is " << sum << '\n';
return 0;
}
Once executed (live here), you can notice that the recursive function has been called more than 10,000,000 times, to calculate up to the 33th Fibonacci number.
That's simply not the right way. Memoization could help, here there's a quick benchmark comparing the recursive functions with a toy implementation of the memoization technique, which is represented by the histogram that you can't see. Because it's 300,000 times shorter than the others.
Still, that's not the "correct" or "natural" way to deal with this problem. As noted in the other answers you could simply calculate each number in sequence, given the previous ones. Enthus3d also noted the pattern in the sequence: odd, odd, even, odd, odd, even, ...
We can go even further and directly calculate only the even terms:
#include <iostream>
int main()
{
const long limit = 4'000'000;
// In the linked question the sequence starts as 1, 2, 3, 5, 8, ...
long long F_0 = 2, F_3 = 8, sum = F_0 + F_3;
for (;;)
{
// F(n+2) = F(n+1) + F(n)
// F(n+3) = F(n+2) + F(n+1) = F(n+1) + F(n) + F(n+1) = 2F(n+1) + F(n)
// F(n+6) = F(n+5) + F(n+4) = F(n+4) + F(n+3) + F(n+3) + F(n+2)
// = 2F(n+3) + F(n+4) + F(n+2) = 3F(n+3) + 2F(n+2)
// = 3F(n+3) + 2F(n+1) + 2F(n) = 3F(n+3) + F(n+3) - F(n) + 2F(n)
long long F_6 = 4 * F_3 + F_0;
if ( F_6 > limit )
break;
sum += F_6;
F_0 = F_3;
F_3 = F_6;
}
std::cout << sum << '\n'; // --> 4613732
return 0;
}
Live here.
If you need multiple Fibonacci numbers, and especially if you need all of them, do not use the recursive approach, use iteration instead:
var prev=0;
var curr=1;
var sum=0;
while(curr<4000000){
if(curr%2==0)
sum+=curr;
var temp=prev;
prev=curr;
curr+=temp;
}
console.log(sum);
The snippet is JavaScript (so it can run here), but if you make var-s to int-s, it will be C-ish enough.
But the actual problem was the loop: you do not need to calculate the first
n (4000000) Fibonacci numbers (which would lead to various overflows), but the Fibonacci numbers which are smaller than 4000000.
If you want a bit of magic, you can also build on the fact that every 3rd Fibonacci number is even, on the basis of "even+odd=>odd", "odd+even=>odd", and only "odd+odd=>even":
0 1 1 2 3 5 8...
E O O E O O E
^ O+O
^ E+O
^ O+E
^ O+O
var prev=1;
var curr=2;
var sum=0;
while(curr<4000000){
sum+=curr;
console.log("elem: "+curr,"sum: "+sum);
for(var i=0;i<3;i++){
var temp=prev;
prev=curr;
curr+=temp;
}
}
And if the question would be only the title, Addition of even fibonacci numbers (let's say, n of them), pure mathematics could do the job, using Binet's formula (described in #Silerus' answer) and the fact that it is an (a^n-b^n)/c thing, where a^n and b^n are geometric sequences, every 3rd of them also being a geometric sequence, (a^3)^n, and the sum of geometric sequences has a simple, closed form (if the series is a*r^n, the sum is a*(1-r^n)/(1-r)).
Putting everything together:
// convenience for JS->C
var pow=Math.pow;
var sqrt=Math.sqrt;
var round=Math.round;
var s5=sqrt(5);
var a=(1+s5)/2;
var a3=pow(a,3);
var b=(1-s5)/2;
var b3=pow(b,3);
for(var i=0;i<12;i++){
var nthEvenFib=round((pow(a3,i)-pow(b3,i))/s5);
var sumEvenFibs=round(((1-pow(a3,i+1))/(1-a3)-(1-pow(b3,i+1))/(1-b3))/s5);
console.log("elem: "+nthEvenFib,"sum: "+sumEvenFibs);
}
Again, both snippets become rather C-ish if var-s are replaced with some C-type, int-s in the first snippet, and mostly double-s in this latter one (the loop variable i can be a simple int of course).
You can use the Binet formula in your calculations - this will allow you to abandon the slow recursive algorithm, another option may be a non-recursive algorithm for calculating fibonacci numbers. https://en.wikipedia.org/wiki/Jacques_Philippe_Marie_Binet. Here is an example of using the Binet formula, it will be much faster than the recursive algorithm, since it does not recalculate all previous numbers.
#include <iostream>
#include <math.h>
using namespace std;
int main(){
double num{},a{(1+sqrt(5))/2},b{(1-sqrt(5))/2},c{sqrt(5)};
int sum{};
for (auto i=1;i<30;++i){
num=(pow(a,i)-pow(b,i))/c;
if (static_cast<int>(num)%2==0)
sum+=static_cast<int>(num);
}
cout<<sum;
return 0;
}
variant 2
int fib_sum(int n)
{
int sum{};
if (n <= 2) return 0;
std::vector<int> dp(n + 1);
dp[1] = 1; dp[2] = 1;
for (int i = 3; i <= n; i++)
{
dp[i] = dp[i - 1] + dp[i - 2];
if(dp[i]%2==0)
sum+=dp[i];
}
return sum;
}
You can speed up brutally by using compile time precalculations for all even Fibonacci numbers and sums using constexpre functions.
A short check with Binets formula shows, that roundabout 30 even Fibonacci numbers will fit into a 64bit unsigned value.
30 numbers can really easily been procealculated without any effort for the compiler. So, we can create a compile time constexpr std::array with all needed values.
So, you will have zero runtime overhead, making you program extremely fast. I am not sure, if there can be a faster solution. Please see:
#include <iostream>
#include <array>
#include <algorithm>
#include <iterator>
// ----------------------------------------------------------------------
// All the following wioll be done during compile time
// Constexpr function to calculate the nth even Fibonacci number
constexpr unsigned long long getEvenFibonacciNumber(size_t index) {
// Initialize first two even numbers
unsigned long long f1{ 0 }, f2{ 2 };
// calculating Fibonacci value
while (--index) {
// get next even value of Fibonacci sequence
unsigned long long f3 = 4 * f2 + f1;
// Move to next even number
f1 = f2;
f2 = f3;
}
return f2;
}
// Get nth even sum of Fibonacci numbers
constexpr unsigned long long getSumForEvenFibonacci(size_t index) {
// Initialize first two even prime numbers
// and their sum
unsigned long long f1{ 0 }, f2{ 2 }, sum{ 2 };
// calculating sum of even Fibonacci value
while (--index) {
// get next even value of Fibonacci sequence
unsigned long long f3 = 4 * f2 + f1;
// Move to next even number and update sum
f1 = f2;
f2 = f3;
sum += f2;
}
return sum;
}
// Here we will store ven Fibonacci numbers and their respective sums
struct SumOfEvenFib {
unsigned long long fibNum;
unsigned long long sum;
friend bool operator < (const unsigned long long& v, const SumOfEvenFib& f) { return v < f.fibNum; }
};
// We will automatically build an array of even numbers and sums during compile time
// Generate a std::array with n elements taht consist of const char *, pointing to Textx...Texty
template <size_t... ManyIndices>
constexpr auto generateArrayHelper(std::integer_sequence<size_t, ManyIndices...>) noexcept {
return std::array<SumOfEvenFib, sizeof...(ManyIndices)>{ { {getEvenFibonacciNumber(ManyIndices + 1), getSumForEvenFibonacci(ManyIndices + 1)}...}};
};
// You may check with Ninets formula
constexpr size_t MaxIndexFor64BitValue = 30;
// Generate the reuired number of texts
constexpr auto generateArray()noexcept {
return generateArrayHelper(std::make_integer_sequence<size_t, MaxIndexFor64BitValue>());
}
// This is an constexpr array of even Fibonacci numbers and its sums
constexpr auto SOEF = generateArray();
// ----------------------------------------------------------------------
int main() {
// Show sum for 4000000
std::cout << std::prev(std::upper_bound(SOEF.begin(), SOEF.end(), 4000000))->sum << '\n';
// Show all even numbers and their corresponding sums
for (const auto& [even, sum] : SOEF) std::cout << even << " --> " << sum << '\n';
return 0;
}
Tested with MSVC 19, clang 11 and gcc10
Compiled with C++17
Welcome to Stack Overflow :)
I have only modified your code on the loop, and kept your Fibonacci implementation the same. I've verified the code's answer on Project Euler. The code can be found below, and I hope my comments help you understand it better.
The three things I've changed are:
1) You tried to look for a number all the way until the 4,000,000 iteration rather than for the number that is less than 4,000,000. That means your program probably went crazy trying to add a number that's insanely large (which we don't need) <- this is probably why your program threw in the towel
2) I improved the check for even numbers; we know that fibonacci sequences go odd odd even, odd odd even, so we only really need to add every third number to our sum instead of checking if the number itself is even <- modulus operations are very expensive on large numbers
3) I added two lines that are commented out with couts, they can help you debug and troubleshoot your output
There's also a link here about using Dynamic Programming to solve the question more efficiently, should anyone need it.
Good luck!
#include <iostream>
using namespace std;
int fibonacci(int i) {
if (i == 2)
return 2;
else if (i == 1)
return 1;
else return fibonacci(i - 1) + fibonacci(i - 2);
}
int main() {
// need to add the sum of all even fib numbers under a particular sum
int max_fib_number = 4000000;
int currentTerm, sum = 0;
currentTerm = 1;
int i = 1;
// we do not need a for loop, we need a while loop
// this is so we can detect when our current number exceeds fib
while(currentTerm < max_fib_number) {
currentTerm = fibonacci(i);
//cout << currentTerm <<"\n";
// notice we check here if currentTerm is a valid number to add
if (currentTerm < max_fib_number) {
//cout << "i:" << i<< "\n";
// we only want every third term
// this is because 1 1 2, 3 5 8, 13 21 34,
// pattern caused by (odd+odd=even, odd+even=odd)
// we also add 1 because we start with the 0th term
if ((i+1) % 3 == 0)
sum += currentTerm;
}
i++;
}
cout << sum;
return 0;
}
Here's Your modified code which produce correct output to the project euler's problem.
#include <iostream>
using namespace std;
int fibonacci(int i) {
if (i == 2)
return 2;
else if (i == 1)
return 1;
else return fibonacci(i - 1) + fibonacci(i - 2);
}
int main() {
int currentsum, sum = 0;
for (int i = 1; i <= 100; i++) {
currentsum = fibonacci(i);
//here's where you doing wrong
if(sum >= 4000000) break; //break when sum reaches 4mil
if(currentsum %2 == 0) sum+=currentsum; // add when even-valued occurs in the currentsum
}
cout << sum;
return 0;
}
Output 4613732
Here's my Code which consists of while loop until 4million occurs in the sum with some explanation.
#include <iostream>
using namespace std;
int main()
{
unsigned long long int a,b,c , totalsum;
totalsum = 0;
a = 1; // 1st index digit in fib series(according to question)
b = 2; // 2nd index digit in fib series(according to question)
totalsum+=2; // because 2 is an even-valued term in the series
while(totalsum < 4000000){ //loop until 4million
c = a+b; // add previous two nums
a = b;
b = c;
if(c&1) continue; // if its odd ignore and if its an even-valued term add to totalsum
else totalsum+=c;
}
cout << totalsum;
return 0;
}
for people who downvoted, you can actually say what is wrong in the code instead downvoting the actual answer to the https://projecteuler.net/problem=2 is the output of the above code 4613732 , competitive programming itself is about how fast can you solve problems instead of clean code.
I have correctly written the program for getting the superdigit of a large number (long long) but can't seem to pass some cases due to timeout and abort calls. Please suggest some optimizations to improve the runtime of my program:
int superDigit(long long m) {
int d=countDigit(m);
if(d==1){
return m;
}
long s=sumDigit(m);
return superDigit(s);
}
//utility functions to calculate digit count and sum of digits
int countDigit(long long n)
{
int count = 0;
while (n != 0) {
n = n / 10;
++count;
}
return count;
}
long sumDigit(long long n)
{
long sum = 0;
while (n != 0) {
sum += n % 10;
n = n / 10;
}
return sum;
}
Theory: A superdigit is defined by the following rules:
If x has only 1 digit, then its super digit is x
Otherwise, the super digit of x is equal to the super digit of the sum of the digits of x
For example:
super_digit(9875): 9+8+7+5 = 29 ,then
super_digit(29): 2 + 9 = 11 ,then
super_digit(11): 1 + 1 = 2 ,then
super_digit(2): = 2
Only looping over the digits once per superDigit call and avoiding recursion should make it faster. Something like this:
long long superDigit(long long m) {
long long sum;
while(true) {
sum = 0;
while(m != 0) {
sum += m % 10;
m /= 10;
}
if(sum >= 10)
m = sum;
else
break;
}
return sum;
}
If you need support for repeated sequences, like 593 10 times (which is usually too big for a long long) you could add a wrapper like this:
long long superDigit(long long m, int times) {
long long r = superDigit(m) * times;
if(r >= 10) r = superDigit(r);
return r;
}
For numbers small enough to fit in a long long, you can check that it works. Example:
superDigit(148148148) == superDigit(148, 3)
If you need support for large numbers that are not repeated sequences, you could add yet another overload, taking the number as a std::string:
long long superDigit(const std::string& m) {
long long sum = 0;
for(auto d : m) sum += d - '0';
if(sum >= 10) return superDigit(sum);
return sum;
}
And you can check that it's also getting the same result as one of the previous overloads:
superDigit(593, 10) == superDigit("593593593593593593593593593593")
I think you are getting abort call for value of m! If the value of m is 0, then the recursion will continue lifetime. And if the value of m can be negative then take care the problem for negative values too.
Please check it!
int superDigit(long long m) {
if(m<=9)return m; // handling case 0
int d=countDigit(m);
if(d==1){
return m;
}
long s=sumDigit(m);
return superDigit(s);
}
Your code has a problem with a '0'. It gets into an endless loop that is terminated if the call stack overflows (if your compiler does not eliminated the tail recursion).
The digit count helper function is completely unnecessary
int superDigit(long long m) {
if(m<10){
return m;
}else{
int s = 0;
do {
s += m % 10;
m = m / 10;
}while (m > 0);
return superDigit(s);
}
}
You can eliminate the recursion by yourself by putting the whole thing into a loop.
int superDigit(long long m) {
while (m >9){
int s = 0;
do {
s += m % 10;
m = m / 10;
}while (m > 0);
m = s;
}
return m;
}
But recursion looks a bit more self explaining and modern compiler should be able to eliminate the tail recursion either.
I am solving a problem which states that we have a list L containing integers from 1 to N. We have to perform the following operation N−1 times:
Choose two elements of the list, let's denote them by X and Y.
Erase the chosen elements from L.
Append the number X + Y + X*Y to L.
At the end, L contains exactly one integer. Find this integer.
As the answer may be large, we have to compute it modulo 10^9 + 7
Constraints :
1≤N≤1,000,000
Time Limit :
1 sec
I have written this code which gives the correct answer in linear time but it says time limit exceeded for this approach. Can someone provide a better optimized solution
inline ull cal(ull x, ull y){
ull ans, i, modno;
modno = 1000000007;
i = 1;
ans = (x + y);
i = (i*x) % modno;
i = (i*y) % modno;
ans = ans + i;
ans = ans % modno;
return ans;
}
int main(){
ull n;
cin>>n;
ull sum, modno;
sum = 0;
modno = 1000000007;
if(n == 1)
cout<<1<<endl;
else
{
sum = n + (n-1) + (n*(n-1));
n -= 2;
do
{
if(n <= 0)
break;
sum = cal(sum, n);
n -= 1;
}while(1);
cout<<ans<<endl;
}
return 0;
}
Final code :
ull n;
cin>>n;
if(n == 1)
cout<<1<<endl;
else
{
ull modno = 1000000007;
ull ans = 1;
ull no = n+1;
while(no >= 1)
{
ans = (ans*no);
if(ans > modno)
ans = ans%modno;
no--;
}
ans = ans - 1;
ans = ans % modno;
cout<<ans<<endl;
There's a closed-form solution for the sum: L = (N+1)!-1
The sum follows this recurrent equation L_N = N + L_(n-1) + N*L_(n-1), L_0=0 which can be obtained by simply always choosing X=L_(N-1) and Y=N ( = the next number to add).
Derivation:
EDIT:
As you posted your final code, I'm posting my benchmark:
#include <iostream>
#include <cstdint>
#include <chrono>
std::uint64_t
factorial(std::uint64_t n) {
std::uint64_t x = 1;
while (n > 1)
x = (x * n--) % 1'000'000'007;
return x;
}
int
main() {
std::uint64_t n;
std::cin >> n;
std::uint64_t numMicro = 0;
for (std::size_t i = 0; i < 1'000; ++i) {
auto start = std::chrono::high_resolution_clock::now();
volatile std::uint64_t res = factorial(n);
auto end = std::chrono::high_resolution_clock::now();
numMicro +=
std::chrono::duration_cast<std::chrono::microseconds>(end - start)
.count();
}
std::cout << "On average: " << numMicro / 1000.0 << "microseconds";
return 0;
}
Compiled with -O3, volatile is there only to make sure that the compiler does not optimize the computation away.
Your solution is almost the same, way below the 1 second. Not sure what to optimize further.
As others have mentioned, the problem boils down to calculating ((n + 1)! - 1) % p. You can search around about fast methods of doing this (fast factorial modulo prime). One of those that would work under 1s is the one mentioned here
Update: Just checked the problem link from codechef. As usual, the trick lies in the constraints which you haven´t accurately described. You have to do the same task for up to 100000 cases. A single fact(n) mod p can be obtained in under 1 second using standard for loop, as n is small.
What won´t work is calculate fact(n) mod p for every test case. Like many other problems, you can benefit using precomputation: build an array where arr[i] is i! mod p up to i = max value n can take + 1. With this information, you can answer each query (test case) in O(1) by just returning (arr[n + 1] - 1) % p.
Just tried this and got accepted. Next time, please add problem link to your description, it is usually the case that you don´t think something is relevant and that part is the whole answer to the problem.
The algorithm should look like this:
sum <- 1
for index <- 2,n
sum = (sum + index + sum * index) mod 1000000007
end for
Explanation: since + and * are commutative and associative, the order in which the items are handled is irrelevant, so you are doing a good job implementing this cycle, but you unnecessarily overcomplicate your cal function.
The other answers tell you to calculate ((n + 1)! - 1) mod modno, which is correct if we forget about the modulo part, but I doubt that calculating ((n + 1)! - 1) mod modno will yield the very same result as computing this in a step-by-step manner regardless of the value of n, because we have + and * in each step. If the other answerers are correct, then you can greatly optimize your algorithm. If not, then optimizing this is not as easy.
The problem just says "Choose two elements of the list, let's denote them by X and Y." and doesn't say anything about the order that the elements need to be chosen.
Therefore it could be rewritten as:
Split the list into one sub-list per CPU
Using SIMD; calculate (X+1)*(Y+1) for each pair in each CPU's
sub-list and store the results in an new list as 64-bit integers so
that you can avoid doing the expensive modulo operation
Using SIMD; calculate (X*Y - 1) % 1000000007 for each pair in
each CPU's new sub-list and store the results as 32-bit integers.
Repeat the previous 2 steps until you're left with one value from
each CPU (and do the final R = (R - 1) % 1000000007 if necessary to bring it back to 32-bit). Store these
values in a list and terminate all threads except for one.
Using SIMD; calculate (X+1)*(Y+1) for each pair
Using SIMD; calculate (X+*Y - 1) % 1000000007 for each pair
Repeat the previous 2 steps until you're left with one value
The sequence of triangle numbers is
generated by adding the natural
numbers. So the 7th triangle number
would be 1 + 2 + 3 + 4 + 5 + 6 + 7 =
28. The first ten terms would be:
1, 3, 6, 10, 15, 21, 28, 36, 45, 55,
...
Let us list the factors of the first
seven triangle numbers:
1: 1
3: 1,3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28
We can see that 28 is the first
triangle number to have over five
divisors.
Given an integer n, display the first
triangle number having at least n
divisors.
Sample Input: 5
Output 28
Input Constraints: 1<=n<=320
I was obviously able to do this question, but I used a naive algorithm:
Get n.
Find triangle numbers and check their number of factors using the mod operator.
But the challenge was to show the output within 4 seconds of input. On high inputs like 190 and above it took almost 15-16 seconds. Then I tried to put the triangle numbers and their number of factors in a 2d array first and then get the input from the user and search the array. But somehow I couldn't do it: I got a lot of processor faults. Please try doing it with this method and paste the code. Or if there are any better ways, please tell me.
Here's a hint:
The number of divisors according to the Divisor function is the product of the power of each prime factor plus 1. For example, let's consider the exponential prime representation of 28:
28 = 22 * 30 * 50 * 71 * 110...
The product of each exponent plus one is: (2+1)*(0+1)*(0+1)*(1+1)*(0+1)... = 6, and sure enough, 28 has 6 divisors.
Now, consider that the nth triangular number can be computed in closed form as n(n+1)/2. We can multiply numbers written in the exponential prime form simply by adding up the exponents at each position. Dividing by two just means decrementing the exponent on the two's place.
Do you see where I'm going with this?
Well, you don't go into a lot of detail about what you did, but I can give you an optimization that can be used, if you didn't think of it...
If you're using the straightforward method of trying to find factors of a number n, by using the mod operator, you don't need to check all the numbers < n. That obviously would take n comparisons...you can just go up to floor(sqrt(n)). For each factor you find, just divide n by that number, and you'll get the conjugate value, and not need to find it manually.
For example: say n is 15.
We loop, and try 1 first. Yep, the mod checks out, so it's a factor. We divide n by the factor to get the conjugate value, so we do (15 / 1) = 15...so 15 is a factor.
We try 2 next. Nope. Then 3. Yep, which also gives us (15 / 3) = 5.
And we're done, because 4 is > floor(sqrt(n)). Quick!
If you didn't think of it, that might be something you could leverage to improve your times...overall you go from O(n) to O(sqrt (n)) which is pretty good (though for numbers this small, constants may still weigh heavily.)
I was in a programming competition way back in school where there was some similar question with a run time limit. the team that "solved" it did as follows:
1) solve it with a brute force slow method.
2) write a program to just print out the answer (you found using the slow method), which will run sub second.
I thought this was bogus, but they won.
see Triangular numbers: a(n) = C(n+1,2) = n(n+1)/2 = 0+1+2+...+n. (Formerly M2535 N1002)
then pick the language you want implement it in, see this:
"... Python
import math
def diminishing_returns(val, scale):
if val < 0:
return -diminishing_returns(-val, scale)
mult = val / float(scale)
trinum = (math.sqrt(8.0 * mult + 1.0) - 1.0) / 2.0
return trinum * scale
..."
First, create table with two columns: Triangle_Number Count_of_Factors.
Second, derive from this a table with the same columns, but consisting only of the 320 rows of the lowest triangle number with a distinct number of factors.
Perform your speedy lookup to the second table.
If you solved the problem, you should be able to access the thread on Project Euler in which people post their (some very efficient) solutions.
If you're going to copy and paste a problem, please cite the source (unless it was your teacher who stole it); and I second Wouter van Niferick's comment.
Well, at least you got a good professor. Performance is important.
Since you have a program that can do the job, you can precalculate all of the answers for 1 .. 320.
Store them in an array, then simply subscript into the array to get the answer. That will be very fast.
Compile with care, winner of worst code of the year :D
#include <iostream>
bool isPrime( unsigned long long number ){
if( number != 2 && number % 2 == 0 )
return false;
for( int i = 3;
i < static_cast<unsigned long long>
( sqrt(static_cast<double>(number)) + 1 )
; i += 2 ){
if( number % i == 0 )
return false;
}
return true;
}
unsigned int p;
unsigned long long primes[1024];
void initPrimes(){
primes[0] = 2;
primes[1] = 3;
unsigned long long number = 5;
for( unsigned int i = 2; i < 1024; i++ ){
while( !isPrime(number) )
number += 2;
primes[i] = number;
number += 2;
}
return;
}
unsigned long long nextPrime(){
unsigned int ret = p;
p++;
return primes[ret];
}
unsigned long long numOfDivs( unsigned long long number ){
p = 0;
std::vector<unsigned long long> v;
unsigned long long prime = nextPrime(), divs = 1, i = 0;
while( number >= prime ){
i = 0;
while( number % prime == 0 ){
number /= prime;
i++;
}
if( i )
v.push_back( i );
prime = nextPrime();
}
for( unsigned n = 0; n < v.size(); n++ )
divs *= (v[n] + 1);
return divs;
}
unsigned long long nextTriNumber(){
static unsigned long long triNumber = 1, next = 2;
unsigned long long retTri = triNumber;
triNumber += next;
next++;
return retTri;
}
int main()
{
initPrimes();
unsigned long long n = nextTriNumber();
unsigned long long divs = 500;
while( numOfDivs(n) <= divs )
n = nextTriNumber();
std::cout << n;
std::cin.get();
}
def first_triangle_number_with_over_N_divisors(N):
n = 4
primes = [2, 3]
fact = [None, None, {2:1}, {3:1}]
def num_divisors (x):
num = 1
for mul in fact[x].values():
num *= (mul+1)
return num
while True:
factn = {}
for p in primes:
if p > n//2: break
r = n // p
if r * p == n:
factn = fact[r].copy()
factn[p] = factn.get(p,0) + 1
if len(factn)==0:
primes.append(n)
factn[n] = 1
fact.append(factn)
(x, y) = (n-1, n//2) if n % 2 == 0 else (n, (n-1)//2)
numdiv = num_divisors(x) * num_divisors(y)
if numdiv >= N:
print('Triangle number %d: %d divisors'
%(x*y, numdiv))
break
n += 1
>>> first_triangle_number_with_over_N_divisors(500)
Triangle number 76576500: 576 divisors
Dude here is ur code, go have a look. It calculates the first number that has divisors greater than 500.
void main() {
long long divisors = 0;
long long nat_num = 0;
long long tri_num = 0;
int tri_sqrt = 0;
while (1) {
divisors = 0;
nat_num++;
tri_num = nat_num + tri_num;
tri_sqrt = floor(sqrt((double)tri_num));
long long i = 0;
for ( i=tri_sqrt; i>=1; i--) {
long long remainder = tri_num % i;
if ( remainder == 0 && tri_num == 1 ) {
divisors++;
}
else if (remainder == 0 && tri_num != 1) {
divisors++;
divisors++;
}
}
if (divisors >100) {
cout <<"No. of divisors: "<<divisors<<endl<<tri_num<<endl;
}
if (divisors > 500)
break;
}
cout<<"Final Result: "<<tri_num<<endl;
system("pause");
}
Boojum's answer motivated me to write this little program. It seems to work well, although it does use a brute force method of computing primes. It's neat how all the natural numbers can be broken down into prime number components.
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <iomanip>
#include <vector>
//////////////////////////////////////////////////////////////////////////////
typedef std::vector<size_t> uint_vector;
//////////////////////////////////////////////////////////////////////////////
// add a prime number to primes[]
void
primeAdd(uint_vector& primes)
{
size_t n;
if (primes.empty())
{
primes.push_back(2);
return;
}
for (n = *(--primes.end()) + 1; ; ++n)
{
// n is even -> not prime
if ((n & 1) == 0) continue;
// look for a divisor in [2,n)
for (size_t i = 2; i < n; ++i)
{
if ((n % i) == 0) continue;
}
// found a prime
break;
}
primes.push_back(n);
}
//////////////////////////////////////////////////////////////////////////////
void
primeFactorize(size_t n, uint_vector& primes, uint_vector& f)
{
f.clear();
for (size_t i = 0; n > 1; ++i)
{
while (primes.size() <= i) primeAdd(primes);
while (f.size() <= i) f.push_back(0);
while ((n % primes[i]) == 0)
{
++f[i];
n /= primes[i];
}
}
}
//////////////////////////////////////////////////////////////////////////////
int
main(int argc, char** argv)
{
// allow specifying number of TN's to be evaluated
size_t lim = 1000;
if (argc > 1)
{
lim = atoi(argv[1]);
}
if (lim == 0) lim = 1000;
// prime numbers
uint_vector primes;
// factors of (n), (n + 1)
uint_vector* f = new uint_vector();
uint_vector* f1 = new uint_vector();
// sum vector
uint_vector sum;
// prime factorize (n)
size_t n = 1;
primeFactorize(n, primes, *f);
// iterate over triangle-numbers
for (; n <= lim; ++n)
{
// prime factorize (n + 1)
primeFactorize(n + 1, primes, *f1);
while (f->size() < f1->size()) f->push_back(0);
while (f1->size() < f->size()) f1->push_back(0);
size_t numTerms = f->size();
// compute prime factors for (n * (n + 1) / 2)
sum.clear();
size_t i;
for (i = 0; i < numTerms; ++i)
{
sum.push_back((*f)[i] + (*f1)[i]);
}
--sum[0];
size_t numFactors = 1, tn = 1;
for (i = 0; i < numTerms; ++i)
{
size_t exp = sum[i];
numFactors *= (exp + 1);
while (exp-- != 0) tn *= primes[i];
}
std::cout
<< n << ". Triangle number "
<< tn << " has " << numFactors << " factors."
<< std::endl;
// prepare for next iteration
f->clear();
uint_vector* tmp = f;
f = f1;
f1 = tmp;
}
delete f;
delete f1;
return 0;
}