Fast way to find a unhappy number - c++

I'm trying to solve a question. Given a range of integers user has to find the number of unhappy present in the given range.
Unhappy number- a number n such that iterating this sum-of-squared-digits map starting with n never reaches the number 1.
I've tried using the brute force approach by calculating the sum of the squares of digits and if at any instant it is equal to any of these (4, 16, 37, 58, 89, 145, 42, 20) then it is a unhappy number.
This approach is giving TLE is there any better method??
Range is between 1 to 10^18.

Your range is between 1 and 1018. This means your numbers have a maximum of 18 digits.
Consider that the maximum square of a digit is 92 = 81, after doing the squared-digit-sum once the maximum number is 18 * 81 = 1458.
So one squared-digit-sum plus a lookup table of ~1500 elements should suffice.
Or two squared-digit-sums plus a lookup table of ~330 elements:
static const bool unhappy[330] {
1,0,1,1,1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,
1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,
1,1,1,0,1,1,0,1,1,1,0,1,1,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,
0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,
1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,0,1,
1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,0,1,1,1,1,1,0,1,1,0
}
inline bool is_unhappy(uint64_t n) {
while (n >= 330) {
int r = 0;
while (n > 0) {
int d = n % 10;
r += d*d;
n /= 10;
}
n = r;
}
return unhappy[n];
}

#include <map>
#include <set>
bool happy(int number) {
static std::map<int, bool> cache;
std::set<int> cycle;
while (number != 1 && !cycle.count(number)) {
if (cache.count(number)) {
number = cache[number] ? 1 : 0;
break;
}
cycle.insert(number);
int newnumber = 0;
while (number > 0) {
int digit = number % 10;
newnumber += digit * digit;
number /= 10;
}
number = newnumber;
}
bool happiness = number == 1;
for (std::set<int>::const_iterator it = cycle.begin();
it != cycle.end(); it++)
cache[*it] = happiness;
return happiness;
}
#include <iostream>
int main() {
for (int i = 1; i < 10; i++)
if (!happy(i))
std::cout << i << std::endl;
return 0;
}
Output:
2
3
4
5
6
8
9
Logic and most of the code taken from here: https://tfetimes.com/c-happy-numbers/

Related

Increasing the speed of this algorithm

I'm trying to make this code run faster, and I am having trouble doing so. I can pass most of my test cases, but as the numbers get larger I cant pass them.
Input: 92871036442 3363728910382456 output: 1160053175781729
Input: 1 1000000000000000000 output: 264160473575034274
These test cases won't pass. What can I do to speed up my algorithm and prevent it from timing out?
#include<iostream>
using namespace std;
bool isLuckyNumber(unsigned long long n)
{
bool found6 = false, found8 = false;
while (n > 0)
{
int digit = n % 10;
if (digit == 6)
{
found6 = true;
}
else if (digit == 8)
{
found8 = true;
}
//removing last digit
n = n / 10;
}
if (found6 && found8)
{
return false;
}
//otherwise if any one of them is true, it is a lucky number
else if (found6 || found8)
{
return true;
}
//otherwise not a lucky number
return false;
}
int main()
{
//creating needed variables, using unsigned long long as data type as it
//can store huge values (between 0 and 18446744073709551615)
unsigned long long L, R, count = 0;
//reading L and R
cin >> L >> R;
//looping as long as L<=R
while (L <= R)
{
//if L is lucky number, incrementing count
if (isLuckyNumber(L))
{
count++;
}
//incrementing L
L++;
}
//displaying count at the end
cout << count << endl;
return 0;
}
Consider the numbers in range 0 - 10n-1, they are the combinations with repetitions of the 10 digits.
The number of combinations without a specified digit is 9n, if you want to exclude two digits is 8n.
Lucky numbers are defined as the set of combinations containing either 6 or 8 but not both. Using basic set theory we can extract some formulas.
N is the total range with cardinality |N| = 10n
N-6, N-8 are the set of number not containing 6 or 8, |N-6| = |N-8| = 9n
N-68, numbers containing neither 6 nor 8, |N-68| = 8n.
From this we can calculate all cardinalities:
|N+6| = |N| - |N-6|
|N+8| = |N| - |N-8|
|N+6| + |N+8| - |N+68| + |N-68| = |N|
|LUCKY| = |N+6| + |N+8| - |N+68| *2 = 2 * ( 9n - 8n )
Now, we need to know the lucky number in a range that is not a power of 10, then we have to split our input in several blocks, each block with the form J * 10^K - (J+1) * 10^K - 1.
The number of such blocks is linear in the input size, that is no more than 10 * [digits of [number + 1]], so the total cost of the algorithm is also linear in the input size, that is log(n) where n is the greatest number in input.
When calculating each block we must take into account J, the prefix:
if J contains both 6 and 8 we can skip the block since the number is
not lucky
if J contains either 6 or 8 but not both, then the formula for this block is |N-8| or |N-6| = 9^K
in the remaining case the formula is 9^K - 8^K.
So, in total:
add 1 to your input numbers since the algorithm exclude the upper bound of the range
slice your number in blocks
calculate the lucky numbers and for each input number, then subtract them to find the result
To do a quick check consider the case where you have the range 1 to 1000000000000000000 (18 digits), since 1 and 1000000000000000000 are not lucky you can directly apply the formula 2 * ( 918 - 8 18 ).
Code:
#include <iostream>
using namespace std;
long countLucky(long number) {
//Algorithm excludes upper bound, so increase it by to include
number++;
long ncopy=number;
//Count digits
int size=0;
while (ncopy>0) {
ncopy/=10;
size++;
}
ncopy=number;
//Extract digits into array
int digits[size];
for (int d=0;ncopy>0;d++) {
digits[d]=ncopy%10;
ncopy/=10;
}
//Calculate powers of 10, 9, 8 starting with size-1
long pow10=1;
long pow9=1;
long pow8=1;
for (int i=0;i<size-1;i++) {
pow10*=10;
pow9*=9;
pow8*=8;
}
bool prefix6=false;
bool prefix8=false;
long count=0;
for (int d=size-1;d>=0;d--) {
//Both digits present in prefix, so no more lucky numbers can be found
if (prefix6 && prefix8) {
break;
}
for (int block=0;block<digits[d];block++) {
if ((prefix6 || (block==6)) && (prefix8 || (block==8))) {
continue;
}
if ((prefix6 || (block==6)) || (prefix8 || (block==8))) {
count+=pow9;
} else {
count+=2*(pow9-pow8);
}
}
//Calculate new powers
pow10/=10;
pow9/=9;
pow8/=8;
//Update prefix status
prefix6 = prefix6 || (digits[d]==6);
prefix8 = prefix8 || (digits[d]==8);
}
cout << endl;
return count;
}
int main() {
long c=countLucky(3363728910382456)-countLucky(92871036442);
cout << "Result " << c << endl;
cout << "Solution " << 1160053175781729 << endl;
}
The idea here is not to test each numbers in that range, but instead you should be finding the answer through number theory.
A way to find the answer, is to first find all the numbers in a range that has the number 6, then find all the numbers in that same range that has the number 8 in it. Then you minus the numbers that have both of them.
Below I have a piece of code that just count the lucky number from any 10^n (which includes 10^0, or 1) to any 10^m:
unsigned long long luckyCount(unsigned long long N)
{
for(auto tempN = N; tempN != 1; tempN /= 10) if(tempN % 10) throw;
// Just some error check, so you can't input any number other than 10^n
unsigned long long T = 0, D = 0, C = 0;
while(N /= 10)
{
D = D * 8 + T * 2;
T = T * 9 + std::pow(10, C);
++C;
}
return T * 2 - D * 2;
}
unsigned long long luckyCount(unsigned long long L, unsigned long long R)
{
return luckyCount(R) - luckyCount(L);
}
int main()
{
unsigned long long L, R;
cin >> L >> R;
std::cout << luckyCount(L, R) << "\n";
}
For each iteration, the amount of number that have a 6 in it and a 8 in it are the same, and both of them are denoted as T. And the amount of numbers that have both 6 and 8 in it are denoted as D.
Hopefully this will give you a starting point, and you algorithm will be running at O(log(N)).
I won't give you a complete algorithm, but just a starting point.
How many lucky numbers are there between 1 and 100?
All the ones in the form 6x + the ones like x6 + 1 (66) + all the 8x + all the x8 + 1 (88), where x can be 0, 1, 2, 3, 4, 5, 7, 9. So there are
(8 + 8 + 1) * 2 = 34 lucky numbers (*).
How many lucky numbers are between a and b?
The ones between 1 and b minus the ones between a and 1.
keep up the reasoning and you'll end up with an algorithm with a complexity better than O(n).
(*) Which are: 6, 8, 16, 18, 26, 28, 36, 38, 46, 48, 56, 58, 60, 61, 62, 63, 64, 65, 66, 67, 69, 76, 78, 80, 81, 82, 83, 84, 85, 87, 88, 89, 96, 98.

Improving optimization of nested loop

I'm making a simple program to calculate the number of pairs in an array that are divisible by 3 array length and values are user determined.
Now my code is perfectly fine. However, I just want to check if there is a faster way to calculate it which results in less compiling time?
As the length of the array is 10^4 or less compiler takes less than 100ms. However, as it gets more to 10^5 it spikes up to 1000ms so why is this? and how to improve speed?
#include <iostream>
using namespace std;
int main()
{
int N, i, b;
b = 0;
cin >> N;
unsigned int j = 0;
std::vector<unsigned int> a(N);
for (j = 0; j < N; j++) {
cin >> a[j];
if (j == 0) {
}
else {
for (i = j - 1; i >= 0; i = i - 1) {
if ((a[j] + a[i]) % 3 == 0) {
b++;
}
}
}
}
cout << b;
return 0;
}
Your algorithm has O(N^2) complexity. There is a faster way.
(a[i] + a[j]) % 3 == ((a[i] % 3) + (a[j] % 3)) % 3
Thus, you need not know the exact numbers, you need to know their remainders of division by three only. Zero remainder of the sum can be received with two numbers with zero remainders (0 + 0) and with two numbers with remainders 1 and 2 (1 + 2).
The result will be equal to r[1]*r[2] + r[0]*(r[0]-1)/2 where r[i] is the quantity of numbers with remainder equal to i.
int r[3] = {};
for (int i : a) {
r[i % 3]++;
}
std::cout << r[1]*r[2] + (r[0]*(r[0]-1)) / 2;
The complexity of this algorithm is O(N).
I've encountered this problem before, and while I don't find my particular solution, you could improve running times by hashing.
The code would look something like this:
// A C++ program to check if arr[0..n-1] can be divided
// in pairs such that every pair is divisible by k.
#include <bits/stdc++.h>
using namespace std;
// Returns true if arr[0..n-1] can be divided into pairs
// with sum divisible by k.
bool canPairs(int arr[], int n, int k)
{
// An odd length array cannot be divided into pairs
if (n & 1)
return false;
// Create a frequency array to count occurrences
// of all remainders when divided by k.
map<int, int> freq;
// Count occurrences of all remainders
for (int i = 0; i < n; i++)
freq[arr[i] % k]++;
// Traverse input array and use freq[] to decide
// if given array can be divided in pairs
for (int i = 0; i < n; i++)
{
// Remainder of current element
int rem = arr[i] % k;
// If remainder with current element divides
// k into two halves.
if (2*rem == k)
{
// Then there must be even occurrences of
// such remainder
if (freq[rem] % 2 != 0)
return false;
}
// If remainder is 0, then there must be two
// elements with 0 remainder
else if (rem == 0)
{
if (freq[rem] & 1)
return false;
}
// Else number of occurrences of remainder
// must be equal to number of occurrences of
// k - remainder
else if (freq[rem] != freq[k - rem])
return false;
}
return true;
}
/* Driver program to test above function */
int main()
{
int arr[] = {92, 75, 65, 48, 45, 35};
int k = 10;
int n = sizeof(arr)/sizeof(arr[0]);
canPairs(arr, n, k)? cout << "True": cout << "False";
return 0;
}
That works for a k (in your case 3)
But then again, this is not my code, but the code you can find in the following link. with a proper explanation. I didn't just paste the link since it's bad practice I think.

problems with Recursion - C++

Given a natural number n (1 <= n <= 500000), please output the summation of all its proper divisors.
Definition: A proper divisor of a natural number is the divisor that is strictly less than the number.
e.g. number 20 has 5 proper divisors: 1, 2, 4, 5, 10, and the divisor summation is: 1 + 2 + 4 + 5 + 10 = 22.
<<--This is a challenge i am trying to do and i am using recursion
int find_sum(std::vector <int> nums,long int sum,int num_now,long int j)
{
if(j<nums[num_now])
{
if(nums[num_now]%j==0)
{
sum=sum+j;
}
return find_sum(nums,sum,num_now,j+1);
}
else
{
return sum;
}
}
sum is the sum of all divisors,nums is the vector i stored number in,num_now is current member in vector,int j is 1 i use it to search for dividers,sadly using this i cant use numbers like 500000 it give's me error,is there any better way to do it or have i made a mistake somewhere.
--Thank you for your time
Here is a recursive way to solve your problem:
int find_sum(int x, int i)
{
if(i == 0)
return 0;
if(x % i == 0)
return i + find_sum(x, (i-1));
return find_sum(x, (i-1));
}
You need to call find_sum(N, N-1); in order to find sum of dividers of N (i must be less than given N because of strict inequality).
In your case it would be find_sum(20, 19);
e.g. my function returns:
71086 for N = 50000
22 for N = 20
0 for N = 1
I don't see the reason why you need to use recursion for solving this problem. I would prefer a more staightforward way to solve it.
long CalculateSumOfDivisors(int number)
{
long sum = 0;
for(int i=1; i<number; i++)
{
// If the remainder of num/i is zero
// then i divides num. So we add it to the
// current sum.
if(number%i==0)
{
sum+=i;
}
}
return sum;
}
Furthermore, we could write a more optimal algorithm, if we note the following:
Let that we have a number n and d is the smallest divisor of n that is greater of 1. (Apparently if the number n is a prime number there is any such a divisor). Then the larget divisor of n is the number n/d.
Based on this we can formulate a more optimal algorithm.
long CalculateSumOfDivisors(int number)
{
int smallestDivisor = FindSmallestDivisor(number);
if(smallestDivisor==1) return 1;
long sum = smallestDivisor;
// Calculate the possible greatest divisor.
int possibleGreatestDivisor = (int)floor(number/smallestDivisor);
for(int i=smallestDivisor+1; i<=possibleGreatestDivisor; i++)
{
if(number%i==0)
{
sum+=i;
}
}
return sum;
}
int FindSmallestDivisor(int number)
{
int smallestDivisor = 1;
for(int i=2; i<number; i++)
{
if(number%i==0)
{
smallestDivisor = i;
break;
}
}
return smallestDivisor;
}
I tried writing code with main function asking user to give the it wants to get sum of. here is the code , hope it helps.
#include<iostream>
using namespace std;
int Sum(int min, int max, int &val, int &sum){
if(min >= max)
return 0;
for ( ; min < max; min++){
if ( val%min == 0){
sum += min + val/min;
return Sum(++min,val/min, val,sum);
}
}
return 0;
}
int main(){
int s=1;
int val;
cout <<"Enter Val to sum:";
cin >> val;
Sum(2,val,val,s);
cout <<"Sum is :"<<s<<endl;
return 0;
}
Here Sum function is used recursively and passed parameters as shown in the code.
Hope it helps.
I don't think you should use recursion.
Instead start by looping from 1..N-1
When you find a divisor adjust the end value for the loop. Example if 2 is a divisor then you know N/2 is also a divisor. And just as important you know there can be no further divisors in the range ]N/2:N[. Likewise if 3 is a divisor then you know N/3 is also a divisor and you know there are no more divisors in the range ]N/3:N[.
Following that concept you can reduced the number of loops significantly for most numbers.
Something like:
long find_sum(int num)
{
long sum = 0;
int max = num;
int i = 1;
while(i < max)
{
if(num % i == 0)
{
sum += i; // Add i to the sum
max = num / i; // Decrement max for performance
if (max != i && max != num)
{
sum += max; // Add max when max isn't equal i
}
}
i++;
}
return sum;
}
Example:
num = 10
sum = 0
i = 1 -> sum = 1, max = 10
i = 2 -> sum = 1+2+5, max = 5
i = 3 -> sum = 1+2+5, max = 5
i = 4 -> sum = 1+2+5, max = 5
i = 5 -> return 8 (1+2+5)
num = 64
sum = 0
i = 1 -> sum = 1, max = 64
i = 2 -> sum = 1+2+32, max = 32
i = 3 -> sum = 1+2+32, max = 32
i = 4 -> sum = 1+2+32+4+16, max = 16
i = 5 -> sum = 1+2+32+4+16, max = 16
i = 6 -> sum = 1+2+32+4+16, max = 16
i = 7 -> sum = 1+2+32+4+16, max = 16
i = 8 -> sum = 1+2+32+4+16+8, max = 8
i = 9 -> return (1+2+32+4+16+8)
The number of loops are kept down by changing max whenever a new divisor is found.

Finding Hamming Numbers - not code or distance

I'm currently learning C++.
I am looking for Hamming numbers (numbers whose prime divisors are less or equal to 5).
When I input a number n, the program should output the n-th Hamming number.
Following numbers are input, and output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ...
1 2 3 4 5 6 8 9 10 12 15 16 18 20 24 ...
Finding Hamming numbers looks easy, but increasing the input number increases run time cost exponentially.
If I input over 1000, it almost costs over 1 second,
and over 1200, it almost costs over 5 seconds.
This is the code I wrote:
while (th > 1)
{
h++;
x = h;
while (x % 2 == 0)
x /= 2;
while (x % 3 == 0)
x /= 3;
while (x % 5 == 0)
x /= 5;
if (x == 1)
th--;
}
So I would like to know how I can find the answer faster.
This algorithm doesn't seem to be very good.
Thanks in advance.
Your code is good if you want to check whether one particular number is a hamming number. When you want to build a list of hamming numbers, it is inefficient.
You can use a bottom-up approach: Start with 1 and then recursively multiply that with 2, 3, and 5 to get all hamming numbers up to a certain limit. You have to take care of duplicates, because you can get to 6 by way of 2·3 and 3·2. A set can take care of that.
The code below will generate all hamming numbers that fit into a 32-bit unsigned int. It fills a set by "spreading" to all hamming numbers. Then it constructs a sorted vector from the set, which you can use to find a hamming number at a certain index:
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
typedef unsigned int uint;
const uint umax = 0xffffffff;
void spread(std::set<uint> &hamming, uint n)
{
if (hamming.find(n) == hamming.end()) {
hamming.insert(n);
if (n < umax / 2) spread(hamming, n * 2);
if (n < umax / 3) spread(hamming, n * 3);
if (n < umax / 5) spread(hamming, n * 5);
}
}
int main()
{
std::set<uint> hamming;
spread(hamming, 1);
std::vector<uint> ordered(hamming.begin(), hamming.end());
for (size_t i = 0; i < ordered.size(); i++) {
std::cout << i << ' ' << ordered[i] << '\n';
}
return 0;
}
This code is faster than your linear method even if you end up creating more hamming numbers than you need.
You don't even need a set if you make sure that you don't construct a number twice. Every hamming number can be written as h = 2^n2 + 3^n3 + 5^n5, so if you find a means to iterate through these uniquely, you're done:
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
typedef unsigned int uint;
int main()
{
const uint umax = 0xffffffff;
std::vector<uint> hamming;
for (uint k = 1;; k *= 2) {
for (uint l = k;; l *= 3) {
for (uint m = l;; m *= 5) {
hamming.push_back(m);
if (m > umax / 5) break;
}
if (l > umax / 3) break;
}
if (k > umax / 2) break;
}
std::sort(hamming.begin(), hamming.end());
for (size_t i = 0; i < hamming.size(); i++) {
std::cout << i << ' ' << hamming[i] << '\n';
}
return 0;
}
The strange break syntax for the loops is required, because we have to check the size before the overflow. If umax*5 were guananteed not to overflow, these conditions could be written in the condition part of the loop.
The code examples in the Rosetta Code link Koshinae posted use similar strategies, but I'm surprised how lengthy some of them are.
In this link you can find two different solutions for finding the nth hamming number. The second method is the optimized one which can get the result in a few seconds.
/* Function to get the nth ugly number*/
unsigned getNthUglyNo(unsigned n)
{
unsigned ugly[n]; // To store ugly numbers
unsigned i2 = 0, i3 = 0, i5 = 0;
unsigned next_multiple_of_2 = 2;
unsigned next_multiple_of_3 = 3;
unsigned next_multiple_of_5 = 5;
unsigned next_ugly_no = 1;
ugly[0] = 1;
for (int i=1; i<n; i++)
{
next_ugly_no = min(next_multiple_of_2,
min(next_multiple_of_3,
next_multiple_of_5));
ugly[i] = next_ugly_no;
if (next_ugly_no == next_multiple_of_2)
{
i2 = i2+1;
next_multiple_of_2 = ugly[i2]*2;
}
if (next_ugly_no == next_multiple_of_3)
{
i3 = i3+1;
next_multiple_of_3 = ugly[i3]*3;
}
if (next_ugly_no == next_multiple_of_5)
{
i5 = i5+1;
next_multiple_of_5 = ugly[i5]*5;
}
} /*End of for loop (i=1; i<n; i++) */
return next_ugly_no;
}

Triangle numbers problem....show within 4 seconds

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