How is this code working for finding the number of divisors of a number? - c++

http://www.spoj.com/problems/NDIV/
This is the problem statement. Since i'm new to programming, this particular problem ripped me off, I found this particular code on the internet which when I tried submitting got AC. I want to know how this code worked, as I have submitted it from online source which itself is bad idea for beginners.
#include <bits/stdc++.h>
using namespace std;
int check[32000];
int prime[10000];
void shieve()
{
for(int i=3;i<=180;i+=2)
{
if(!check[i])
{
for(int j=i*i;j<=32000;j+=i)
check[j]=1;
}
}
prime[0] = 2;
int j=1;
for(int i=3;i<=32000;i+=2)
{
if(!check[i]){
prime[j++]=i;
}
}
}
int main()
{
shieve();
int a,b,n,temp,total=1,res=0;
scanf("%d%d%d",&a,&b,&n);
int count=0,i,j,k;
for(i=a;i<=b;i++)
{
temp=i;
total=1;
k=0;
for(j=prime[k];j*j<=temp;j=prime[++k])
{
count=0;
while(temp%j==0)
{
count++;
temp/=j;
}
total *=count+1;
}
if(temp!=1)
total*=2;
if(total==n)
res++;
}
printf("%d\n",res);
return 0;
}
It looks like the code works on the sieve of eratosthenes, but a few things i'm unable to understand.
Why the limit of array "check" is 32000?
Again why the limit for array prime is 10000?
Inside main, whatever is happening inside the for loop of j.
Too many confusions regarding this approach, can someone explain the whole algorithm how it's working.

The hard limit on the arrays is set probably because the problem demands so? If not then just bad code.
Inside the inner loop, you are calculating the largest power of a prime that divides the number. Why? See point 3.
The number of factors of a number n can be calculated as follows:
Let n = (p1)^(n1) * (p2)^(n2) ... where p1, p2 are primes and n1, n2 ... are their exponents. Then the number of factors of n = (n1 + 1)*(n2 + 1)...
Hence the line total *= count + 1 which is basically total = total * (count + 1) (where count is the largest exponent of the prime number that divides the original number) calculates the number of prime factors of the number.
And yes, the code implements sieve of Eratosthenes for storing primes in a table.
(Edit Just saw the problem - you need at least 10^4 boolean values to store the primes (you don't actually need to store the values, just a flag indicating whether the values are prime or not). The condition given is 0 <= b - a <= 10^4 , So start your loop from a to b and check for the bool values stored in the array to know if they are prime or not.)

Related

why do we iterate to root(n) to check if n is a perfect number

while checking if a number n is perfect or not why do we check till square root of (n)?
also can some body explain the if conditions in the following loop
for(int i=2;i<sqrt(n);i++)
{
if(n%i==0)
{
if(i==n/i)
{
sum+=i; //Initially ,sum=1
}
else
{
sum+=i+(n/i);
}
}
}
According to number theory, any number has at least 2 divisors (1, the number itself), and if the number A is a divisor of the number B, then the number B / A is also a divisor of the number B. Now consider a pair of numbers X, Y, such that X * Y == B. If X == Y == sqrt(B), then it is obvious that X, Y <= sqrt(B). If we try to increase Y, then we have to reduce X so that their product is still equal to B. So it turns out that among any pair of numbers X, Y, which in the product give B, at least one of the numbers will be <= sqrt(B). Therefore it is enough to find simply all divisors of number B which <= sqrt(B).
As for the loop condition, then sqrt(B) is a divisor of the number B, but we B / sqrt(B) is also a divisor, and it is equal to sqrt(B), and so as not to add this divisor twice, we wrote this if (but you have to understand that it will never be executed, because your loop is up to sqrt(n) exclusively).
It's pretty simple according to number theory:
If N has a factor i, it'll also has a factor n/i (1)
If we know all factors from 1 -> sqrt(n), the rest can be calculated by applying (1)
So that's why you only have to check from 1 -> sqrt(n). However, you code didn't reach the clause i==n/i which is the same as i == sqrt(n), so if N is a perfect square, sqrt(n) won't be calculated.
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int n; cin >> n;
int sum = 1;
for(int i=2;i<sqrt(n);i++)
{
if(n%i==0)
{
if(i==n/i) { sum+=i; }
else { sum+=i+(n/i); }
}
}
cout << sum;
}
Input : 9
Output : 1
As you can see, the factor 3 = sqrt(9) is missed completely. To avoid this, use i <= sqrt(n), or to avoid using sqrt(), use i <= n/i or i*i <= n.
Edit :
As #HansOlsson and #Bathsheba mentioned, there're no odd square which are perfect number (pretty easy to prove, there's even no known odd perfect number), and for even square, there's a proof here. So the sqrt(n) problem could be ignored in this particular case.
However, in other cases when you just need to iterate over the factors some error may occurred. It's better using the right method from the start, than trying to track bugs down afterward when using this for something else.
A related post : Why do we check up to the square root of a prime number to determine if it is prime?
The code uses the trick of finding two factors at once, since if i divides n then n/i divides n as well, and normally adds both of them (else-clause).
However, you are missing the error in the code: it loops while i<sqrt(n) but has code to handle i*i=n (the then-clause - and it should only add i once in that case), which doesn't make sense as both of these cannot be true at the same time.
So the loop should be to <=sqrt(n), even if there are no square perfect numbers. (At least I haven't seen any square perfect numbers, and I wouldn't be surprised if there's a simple proof that they don't exist at all.)

Given an integer n, return the number of ways it can be represented as a sum of 1s and 2s

For example:
5 = 1+1+1+1+1
5 = 1+1+1+2
5 = 1+1+2+1
5 = 1+2+1+1
5 = 2+1+1+1
5 = 1+2+2
5 = 2+2+1
5 = 2+1+2
Can anyone give a hint for a pseudo code on how this can be done please.
Honestly have no clue how to even start.
Also this looks like an exponential problem can it be done in linear time?
Thank you.
In the example you have provided order of addends is important. (See the last two lines in your example). With this in mind, the answer seems to be related to Fibonacci numbers. Let's F(n) be the ways n can be written as 1s and 2s. Then the last addened is either 1 or 2. So F(n) = F(n-1) + F(n-2). These are the initial values:
F(1) = 1 (1 = 1)
F(2) = 2 (2 = 1 + 1, 2 = 2)
This is actually the (n+1)th Fibonacci number. Here's why:
Let's call f(n) the number of ways to represent n. If you have n, then you can represent it as (n-1)+1 or (n-2)+2. Thus the ways to represent it are the number of ways to represent it is f(n-1) + f(n-2). This is the same recurrence as the Fibonacci numbers. Furthermore, we see if n=1 then we have 1 way, and if n=2 then we have 2 ways. Thus the (n+1)th Fibonacci number is your answer. There are algorithms out there to compute enormous Fibonacci numbers very quickly.
Permutations
If we want to know how many possible orderings there are in some set of size n without repetition (i.e., elements selected are removed from the available pool), the factorial of n (or n!) gives the answer:
double factorial(int n)
{
if (n <= 0)
return 1;
else
return n * factorial(n - 1);
}
Note: This also has an iterative solution and can even be approximated using the gamma function:
std::round(std::tgamma(n + 1)); // where n >= 0
The problem set starts with all 1s. Each time the set changes, two 1s are replaced by one 2. We want to find the number of ways k items (the 2s) can be arranged in a set of size n. We can query the number of possible permutations by computing:
double permutation(int n, int k)
{
return factorial(n) / factorial(n - k);
}
However, this is not quite the result we want. The problem is, permutations consider ordering, e.g., the sequence 2,2,2 would count as six distinct variations.
Combinations
These are essentially permutations which ignore ordering. Since the order no longer matters, many permutations are redundant. Redundancy per permutation can be found by computing k!. Dividing the number of permutations by this value gives the number of combinations:
Note: This is known as the binomial coefficient and should be read as "n choose k."
double combination(int n, int k)
{
return permutation(n, k) / factorial(k);
}
int solve(int n)
{
double result = 0;
if (n > 0) {
for ( int k = 0; k <= n; k += 1, n -= 1 )
result += combination(n, k);
}
return std::round(result);
}
This is a general solution. For example, if the problem were instead to find the number of ways an integer can be represented as a sum of 1s and 3s, we would only need to adjust the decrement of the set size (n-2) at each iteration.
Fibonacci numbers
The reason the solution using Fibonacci numbers works, has to do with their relation to the binomial coefficients. The binomial coefficients can be arranged to form Pascal's triangle, which when stored as a lower-triangular matrix, can be accessed using n and k as row/column indices to locate the element equal to combination(n,k).
The pattern of n and k as they change over the lifetime of solve, plot a diagonal when viewed as coordinates on a 2-D grid. The result of summing values along a diagonal of Pascal's triangle is a Fibonacci number. If the pattern changes (e.g., when finding sums of 1s and 3s), this will no longer be the case and this solution will fail.
Interestingly, Fibonacci numbers can be computed in constant time. Which means we can solve this problem in constant time simply by finding the (n+1)th Fibonacci number.
int fibonacci(int n)
{
constexpr double SQRT_5 = std::sqrt(5.0);
constexpr double GOLDEN_RATIO = (SQRT_5 + 1.0) / 2.0;
return std::round(std::pow(GOLDEN_RATIO, n) / SQRT_5);
}
int solve(int n)
{
if (n > 0)
return fibonacci(n + 1);
return 0;
}
As a final note, the numbers generated by both the factorial and fibonacci functions can be extremely large. Therefore, a large-maths library may be needed if n will be large.
Here is the code using backtracking which solves your problem. At each step, while remembering the numbers used to get the sum so far(using vectors here), first make a copy of them, first subtract 1 from n and add it to the copy then recur with n-1 and the copy of the vector with 1 added to it and print when n==0. then return and repeat the same for 2, which essentially is backtracking.
#include <stdio.h>
#include <vector>
#include <iostream>
using namespace std;
int n;
void print(vector<int> vect){
cout << n <<" = ";
for(int i=0;i<vect.size(); ++i){
if(i>0)
cout <<"+" <<vect[i];
else cout << vect[i];
}
cout << endl;
}
void gen(int n, vector<int> vect){
if(!n)
print(vect);
else{
for(int i=1;i<=2;++i){
if(n-i>=0){
std::vector<int> vect2(vect);
vect2.push_back(i);
gen(n-i,vect2);
}
}
}
}
int main(){
scanf("%d",&n);
vector<int> vect;
gen(n,vect);
}
This problem can be easily visualized as follows:
Consider a frog, that is present in front of a stairway. It needs to reach the n-th stair, but he can only jump 1 or 2 steps on the stairway at a time. Find the number of ways in which he can reach the n-th stair?
Let T(n) denote the number of ways to reach the n-th stair.
So, T(1) = 1 and T(2) = 2(2 one-step jumps or 1 two-step jump, so 2 ways)
In order to reach the n-th stair, we already know the number of ways to reach the (n-1)th stair and the (n-2)th stair.
So, once can simple reach the n-th stair by a 1-step jump from (n-1)th stair or a 2-step jump from (n-2)th step...
Hence, T(n) = T(n-1) + T(n-2)
Hope it helps!!!

sieve or eratosthenes calculator -- running into memory issues and crashing with numbers >=1,000,000

I'm not exactly sure why this is. I tried changing the variables to long long, and I even tried doing a few other things -- but its either about the inefficiency of my code (it literally does the whole process of finding all primes up to the number, then checking against the number to see if its divisible by that prime -- very inefficient, but its my first attempt at this and I feel pretty accomplished having it work at all....)
Or the fact that it overflows the stack. Im not sure where it is exactly, but all I know is that it MUST be related to memory and the way its dealing with the number.
If I had to guess, Id say its a memory issue happening when it is dealing with the prime number generation up to that number -- thats where it dies even if I remove the check against the input number.
I'll post my code -- just be aware, I didnt change long long back to int in a few places, and I also have a SquareRoot Variable that is not used, because it was supposed to try and help memory efficiency but was not effective the way I tried to do it. I Just never deleted it. I will clean up the code when and if I can successfully finish it.
As far as I am aware though, it DOES work pretty reliably for 999,999 and down, I actually checked it up against other calculators of the same type and it seemingly does generate the proper answers.
If anyone can help or explain what I screwed up here, your helping a guy trying to learn on his own without any school or anything. so its appreciated.
#include <iostream>
#include <cmath>
void sieve(int ubound, int primes[]);
int main()
{
long long n;
int i;
std::cout << "Input Number: ";
std::cin >> n;
if (n < 2) {
return 1;
}
long long upperbound = n;
int A[upperbound];
int SquareRoot = sqrt(upperbound);
sieve(upperbound, A);
for (i = 0; i < upperbound; i++) {
if (A[i] == 1 && upperbound % i == 0) {
std::cout << " " << i << " ";
}
}
return 0;
}
void sieve(int ubound, int primes[])
{
long long i, j, m;
for (i = 0; i < ubound; i++) {
primes[i] = 1;
}
primes[0] = 0, primes[1] = 0;
for (i = 2; i < ubound; i++) {
for(j = i * i; j < ubound; j += i) {
primes[j] = 0;
}
}
}
If you used legal C++ constructs instead of non-standard variable length arrays, your code will run (whether it produces the correct answers is another question).
The issue is more than likely that you're exceeding the limits of the stack when you declare arrays with a million or more elements.
Therefore instead of this:
long long upperbound = n;
A[upperbound];
Use std::vector:
#include <vector>
//...
long long upperbound = n;
std::vector<int> A(upperbound);
and then:
sieve(upperbound, A.data());
The std::vector does not use the stack space to allocate its elements (unless you have written an allocator for it that uses the stack).
As a matter of fact, you don't even need to pass upperbound to sieve, as a std::vector knows its own size by calling the size() member function. But I leave that as an exercise.
Live example using 2,000,000
First of all, read and apply PaulMcKenzie's advice. That's the most important thing. I'm only addressing some teeny bits of your question that remained open.
It seems that you are trying to factor the number that you misleadingly called upperbound. The mysterious role of the square root of this number is related to this fact: if the number is composite at all - and hence can be computed as the product of some prime factors - then the smallest of these prime factors cannot be greater than the square root of the number. In fact, only one factor can possibly be greater, all others cannot exceed the square root.
However, in its present form your code cannot draw advantage from this fact. The trial division loop as it stands now has to run up to number_to_be_factored / 2 in order not to miss any factors because its body looks like this:
if (sieve[i] == 1 && number_to_be_factored % i == 0) {
std::cout << " " << i << " ";
}
You can factor much more efficiently if you refactor your code a bit: when you have found the smallest prime factor p of your number then the remaining factors to be found must be precisely those of rest = number_to_be_factored / p (or n = n / p, if you will), and none of the remaining factors can be smaller than p. However, don't forget that p might occur more than once as a factor.
During any round of the proceedings you only need to consider the prime factors between p and the square root of the current number; if none of those primes divides the current number then it must be prime. To test whether p exceeds the square root of some number n you can use if (p * p > n), which is computationally more efficient that actually computing the square root.
Hence the square root occurs in two different roles:
the square root of the number to be factored limits the amount of sieving that needs to be done
during the trial division loop, the square root of the current number gives an upper bound for the highest prime factor that you need to consider
That's two faces of the same coin but two different usages in the actual code.
Note: once you got your code working by applying PaulMcKenzie's advice, you might also to consider posting over on Code Review.

Problems with program which find prime number from 1 to 100

I wrote this program which find and displays prime numbers from 1 to 100
int ifprime (int n)
{
int i=1;
while (i<= n)
{
i++;
if (n%i == 0)
{
return false;
break;
}
else continue;
}
return true;
}
int prime_numbers (void)
{
bool result;
for (int i = 2; i<=100; ++i)
{
result = ifprime(i);
if (result==true) cout<<i<<endl;
else continue;
}
}
int main()
{
prime_numbers();
return 0;
}
The program displays nothing. Why?
Change your loop to:
for(int i=2; i<n; i++){
if(n%i==0){
return false;
}
}
Or your while end condition to:
while(i < n-1)
As pointed out in the comments, every non-zero number is divisible by 1 and itself. Change this line (line 4)
while (i<= n)
to
while (i< n)
If that's your whole code, then you're simply missing a main() function.
Though it shouldn't link without a main() function.
There are some additional problems with your code, but that's probably the reason why you don't see any output.
Try adding this to your file:
int main()
{
prime_numbers();
return 0;
}
Many people have pointed out the problem with:
while (i <= n)
...because you allow i to be n in your for loop, every natural number is divisible by itself so it wrongly accuses prime numbers of being composites. As people pointed out, the quick fix is:
while (i < n)
But the reason why I reply is because there are other things you can do to make your code better. The first improvement is that you don't need to try dividing by numbers greater than the square root of n because if there is a greater than it, then there is also a divisor less than it. So you could do something like this:
while (i*i <= n)
But there are further improvements you can do on that. For example, why should you have to compute i*i every iteration? If you pre-compute square root of n (rounded to int), then you can avoid that computation.
Another optimization is that you can avoid trial dividing by half of the numbers: if n is not divisible by 2, then no reason to try any other even numbers. So you can jump i by 2 every time in your inner loop. There are other tricks if you want to eliminate trial dividing by numbers divisible by 3.
Really, however, there is a nice super-duper fast algorithm to find the first x primes if you don't mind using order x bytes of memory. It is called the sieve of Eratosthenes, and it is really fun to implement. Once you get your current code optimized, I recommend trying the sieve.
The problem of finding prime numbers efficiently has received an enormous amount of attention in the academic literature, and it is now considered solved. But it takes a lot of study to learn it.

Code with prime numbers

I am trying to solve one problem from on-line judging system. I have a solution which works, but not efficient enough. Here is the problem:
Which the least number n can we imagine in product n = a∙b like k ways? Products a∙b and b∙a is one of the way, where all numbers is natural (1≤ k ≤50).
Input One number k.
Output One number n.
My code did not pass four tests. It is too slow for k=31, 37, 47. I have been thinking on this problem 2 days,but no improvement. Here is my code, please share, if you have any ideas.
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
int prime[10000];
long x,j,i,flag,k,length,p,checker,count,number;
int main()
{
prime[0]=2;
scanf("%ld",&k);
//I find prime numbers between 1 and 1000. 1000 can be changed, just for testing
for (i=3;i<=1000;i=i+2)
{
flag=0;
for (j=2;j<=sqrt(i);j++)
{
if(i%j==0)
{
flag=1;
break;
}
}
if(flag==0)
{
x++;
prime[x]=i;
}
}
length=x;
//this loop is too big I know, again for testing. I suspect, there must be a way to make some changes to this for loop
for (i=1;i<10000000000;i++)
{
number=i;
p=1;
for(x=0;x<=length;x++)
{
if(prime[x]>sqrt(i))
break;
count=0;
while(number%prime[x]==0)
{
number=number/prime[x];
count++;
}
p=p*(count+1);
//I find prime factors of numbers and their powers, then calculate number of divisors
}
//printf("%d\n",p);
//number of ways is just number of divisors/2 or floor (divisors/2)+1
if(p%2==0)
checker=p/2;
else
checker=floor(p/2)+1;
if(checker==k)
{
printf("%ld\n",i);
break;
}
}
return 0;
}
If I understand the problem correctly it's asking you which is the least number n with exactly 2k divisors (should I consider 1 and n?)
in fact if a number has a divisor a, then n / a = b is an integer and n = a* b (counting only one time a and b, so you should divide by two the number of divisors)
edit
Doing that is time consuming indeed. So this is the idea;
for a number n in the form n = p1^(a1)*p2^(a2)...pn^(an) (this is the prime factorization of the number) the number of divisor is (a1 + 1)(a2+1)...(an+1)
Hence, if you want to find a number that has k divisor, factorize k. then assign the biggest factor to the smallest prime; eg if k = 2*5*7, then n should be 2^7*3^5*5^2
I know it is not since i didnt take into account that (a, b) is equal to (b, a) but play around it a little and it should work
example
take k = 37. Then double the number - (to consider the symmetry). You get 74.
Now, if you can imagine n as n = n * 1, then you just need to factor 74 (that is 2 * 37);
then give 36 to 2 and 1 to 3, leading n = 2^(36)*3 = 206158430208
if you can't, then you need to add 1 to the number you got previously (in this case, 74 + 1 = 75 = 25*3); this way you get n = 2^24 * 3^2 = 150994944
If it's none of the above, then I am probably wrong...