CODECHEF NOV13 PRETNUM

Problem Statement

Given a range to b, we have to all numbers which have prime number of divisors.

Eg: In the range 1 to 10 , the numbers are 2, 3, 4, 5, 7, 9

For a brief problem statement visit this link.

Solution

what is a divisor ? If ‘x’ divides ‘y’, then ‘x’ is a divisor of ‘y’. Eg: ‘2’ is a divisor of ‘4’.

PROBLEM ANALYSIS :

  • We need to count numbers having prime number of divisors. Except 2, all primes are odd numbers. This shows that we need to look for only numbers having odd number of divisors. Only Square Numbers  have odd number of divisors.
  • Only prime numbers have 2 divisors

Thus, the problem is reduced to finding ” PRIME NUMBERS ” and “SQUARE NUMBERS“(which are prime) within the given range.

Pre-requisites

Sieve of Eratosthenes:

Let  us  say that u need to find primes upto ‘n’.

First make a list of numbers from 2 to n

Then, take the number ‘2’ and remove all multiples from the list. Then take the next number ( 3 ), then remove its multiples. Then, the take the next number ‘5’ and remove its multiples. Continue this process until the end of list.

Note: is not taken as it is removed from the list by 2.


EFFICIENT WAY TO FIND NUMBER OF DIVISORS OF A NUMBER:

Let us consider a number ‘x’

The number x can be expressed in terms of prime numbers

x = ( p1 )e1 * (p2) e2 * (p3) e3 * . . . . . . . . . . . . * (pk) ek

Eg: 36  = 22 * 32

Number of divisors of number = ( 1 + e1 ) * (1 + e2) * ……… * (1 + ek)

Eg: For 36, it is ( 1 + 2 ) * ( 1 + 2 ) = 9

EFFICIENT WAY TO FIND NUMBER OF PRIME NUMBERS IN A RANGE( a, b ):

In the Problem Statement , it is specified that and  can take values from 1 to 10 ^ 12.

Range ( b – a ) is <= 10 ^ 6

We can use Sieve of Eratosthenes, to compute prime numbers in a range quickly. I used the idea from this popular blog.

Example:

Say we need to find prime numbers from 10′ to  ’30’.

First, create a list called primes which contain prime numbers upto SQRT(30).  The primes list will contain numbers 2, 3, 5.

Then, make a list called result of size of 21 ( 30 – 10 + 1 ). The index ‘0’ in this list correspond to ’10’ and index ’20’ correspond to ’30’.

Take the first prime ‘2’ from primes list .Find multiple of 2 which is nearest to 10.

It is ’10’. Its index is ‘0’. Set the flag for that index false and remove all the multiples of ‘2’ from the result list.

Now, take all primes from the list and continue the same process.

CODE:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<vector>
using namespace std;
#define LL long long
vector<int> primes;
vector<bool> isPrime(1000001,false);

void precompute()
{
	vector<bool> flag(1000001,true);
	int i,j,k;
	primes.push_back(2);
	isPrime[2] = true;

	for(i=3;i<=1000001;i+=2)
		if( flag[i] )
		{
			primes.push_back(i);
			isPrime[i] = true;
			for( j = i,k = i*2; j <= 1000001; j+=k )
				flag[j] = false;
		}
}

int divisors(int num)
{
	int cnt = 0,finalCount = 1,i = 0;
	bool is = false;

	while( i < primes.size() && num > 1 )
	{
		cnt = 0;
		while( num > 1 && num % primes[i] == 0 )
		{
			num /= primes[i];
			cnt++;
		}

		if( cnt )
			is = true;

		finalCount *= (cnt*2 + 1);
		i++;
	}
	if( num > 1 )
		finalCount *= 3;

	if( is )
		return finalCount;

	return 0;
}

int countPrimes(long long int l,long long int r)
{
	if( l == 1LL )
		l++;
	vector<bool> fc(1000002,true);
	int i = 0,cnt,low,high = r - l,k;

	while( i < primes.size() )
	{
		long long int first = l + ( primes[i] - (l % primes[i]) ) % primes[i];

		if( first == primes[i] )
			first += primes[i];

		low = first - l;

		while( low <= high )
		{
			fc[low] = false;
			low += primes[i];
		}

		i++;
	}
	cnt = 0;
	i = 0;
	while( i <= high )
	{
		if( fc[i] )
			cnt++;
		i++;
	}

	return cnt;
}

int findCount(long long int l,long long int r)
{
	int low = sqrt(l);
	int d,count = 0;

	if( ((LL)low * (LL)low) < l )
		low++;

	while( ( (LL)low * (LL)low )  <= r )
	{
		d = divisors(low);
		if( isPrime[d] )
			count++;
		low ++;
	}

	return count;
}

int main()
{
	std::ios_base::sync_with_stdio(false);
	precompute();
	int t;
	cin>>t;
	while(t--)
	{
		long long int l,r;
		cin>>l>>r;
		cout<<findCount(l,r) + countPrimes(l,r)<<"\n";
	}
}

Leave a comment