How many numbers in interval with k(odd) number of divisors?
by hemangsarkar, Nov 26, 2016, 7:41 PM
The problem is http://www.spoj.com/problems/ODDDIV/
We need to find the number of numbers in a given interval with k (an odd number) of divisors.
The interval can be
in the worst case.
first observation
How to find number of divisors
How to find number of divisors 2
This should have worked?
Final Step
We need to find the number of numbers in a given interval with k (an odd number) of divisors.
The interval can be

first observation
The number of divisors is k which is an odd number. Only perfect squares have odd number of divisors.
So once we are given an interval say [low, high] - all we need to do is to see how many perfect squares in this interval have k divisors.
sqrt(high) will give the last perfect square in this interval but sqrt(low) might not be the first perfect square in this interval.
k = sqrt(low)
if(k*k<low)
k++;
k now is the smallest perfect square in the interval.
So once we are given an interval say [low, high] - all we need to do is to see how many perfect squares in this interval have k divisors.
sqrt(high) will give the last perfect square in this interval but sqrt(low) might not be the first perfect square in this interval.
k = sqrt(low)
if(k*k<low)
k++;
k now is the smallest perfect square in the interval.
How to find number of divisors
int divisors(int x)
{
int y = sqrt(x);
int count = 0;
for(int i = 1; i<=y; i++)
{
if(x%i==0)
count = count + 2; //this is because both i and x/i are divisors of x
}
if(y*y==x)
count = count - 1; //this is because we are counting y twice. here i will be x/i.
return count;
}
We can use the above function and iterate over the perfect squares in the interval to check how many of them have k divisors.
This method of counting divisors takes
time for input number
. The worst case for the interval
will take
too much time and the time limit will be exceeded.
There are
number of perfect squares less or equal to
.
{
int y = sqrt(x);
int count = 0;
for(int i = 1; i<=y; i++)
{
if(x%i==0)
count = count + 2; //this is because both i and x/i are divisors of x
}
if(y*y==x)
count = count - 1; //this is because we are counting y twice. here i will be x/i.
return count;
}
We can use the above function and iterate over the perfect squares in the interval to check how many of them have k divisors.
This method of counting divisors takes


![$[1, 10^{10}]$](http://latex.artofproblemsolving.com/1/b/e/1bec8a4785b6e4ec87cea403806bd860ed89027f.png)
too much time and the time limit will be exceeded.
There are


How to find number of divisors 2
Can we relate the number of factors of
to the number of factors of
?
Let
where all
are prime numbers.
Then
will have
number of divisors.
We think in terms of sieve of Eratosthenes to find the smallest prime number that divides a given number x.
This link gives a method to do so: http://codeforces.com/blog/entry/7262
Once this is done, the number of divisors of a number x is easy to find.
sp[x] stores the smallest prime factor of x as in the link above.
int divi,prod,count,j;
int ans[100005];
for(int i = 1; i<=100000; i++)
{
prod = 1;
count = 0;
j = i;
while(j>1)
{
divi = sp[j];
while(j%divi==0)
{
count++;
j = j/divi;
}
prod = prod*(2*count+1);
count = 0; //reset count to 0 for the next prime factor
}
ans = prod; //ans stores the number of divisors of i*i
}


Let


Then


We think in terms of sieve of Eratosthenes to find the smallest prime number that divides a given number x.
This link gives a method to do so: http://codeforces.com/blog/entry/7262
Once this is done, the number of divisors of a number x is easy to find.
sp[x] stores the smallest prime factor of x as in the link above.
int divi,prod,count,j;
int ans[100005];
for(int i = 1; i<=100000; i++)
{
prod = 1;
count = 0;
j = i;
while(j>1)
{
divi = sp[j];
while(j%divi==0)
{
count++;
j = j/divi;
}
prod = prod*(2*count+1);
count = 0; //reset count to 0 for the next prime factor
}
ans = prod; //ans stores the number of divisors of i*i
}
This should have worked?
Well now that we have precomputed and stored the number of divisors of every perfect square from
to
, we can simply
iterator over our interval and see which perfect squares have k number of divisors.
This should work, shouldn't it? It will give Time Limit Exceeded again. Why this time?
Too many test cases.
How do we tackle this?
We can store the numbers for every k possible. We use an array of vectors:
vector<int> a[10001];
Now a[k] will be a vector where we push_back every square root of every number which has k divisors. We add one statement in our last snippet:
ans = prod; //ans stores the number of divisors of i*i
a[prod].push_back(i); //i*i has prod number of divisors.


iterator over our interval and see which perfect squares have k number of divisors.
This should work, shouldn't it? It will give Time Limit Exceeded again. Why this time?
Too many test cases.
How do we tackle this?
We can store the numbers for every k possible. We use an array of vectors:
vector<int> a[10001];
Now a[k] will be a vector where we push_back every square root of every number which has k divisors. We add one statement in our last snippet:
ans = prod; //ans stores the number of divisors of i*i
a[prod].push_back(i); //i*i has prod number of divisors.
Final Step
//lowps*lowps is the smallest perfect square in the given interval
//upps*upps is the largest perfect square in the given interval
//k is the number of divisors we are looking for
//note that binary search on a[k] is possible because it is sorted
int find(long long lowps, long long upps, long long k)
{
vector<int>::iterator itl,itr;
itl = lower_bound(a[k].begin(), a[k].end(), lowps);//first number in a[k] not less than lowps
itr = upper_bound(a[k].begin(), a[k].end(), upps);//first number in a[k] greater than upps
if(itl == a[k].end()) //this is so when every number in the list is less than lowps
return 0;
itr--;
return (itr - itl + 1);
}
//to know about lower_bound in detail: http://www.cplusplus.com/reference/algorithm/lower_bound/
//to know about upper_bound in detail: http://www.cplusplus.com/reference/algorithm/upper_bound/
We use slight variants of binary search to find the answer quickly. Now the number of test cases in the problem shouldn't be a problem.
//upps*upps is the largest perfect square in the given interval
//k is the number of divisors we are looking for
//note that binary search on a[k] is possible because it is sorted
int find(long long lowps, long long upps, long long k)
{
vector<int>::iterator itl,itr;
itl = lower_bound(a[k].begin(), a[k].end(), lowps);//first number in a[k] not less than lowps
itr = upper_bound(a[k].begin(), a[k].end(), upps);//first number in a[k] greater than upps
if(itl == a[k].end()) //this is so when every number in the list is less than lowps
return 0;
itr--;
return (itr - itl + 1);
}
//to know about lower_bound in detail: http://www.cplusplus.com/reference/algorithm/lower_bound/
//to know about upper_bound in detail: http://www.cplusplus.com/reference/algorithm/upper_bound/
We use slight variants of binary search to find the answer quickly. Now the number of test cases in the problem shouldn't be a problem.
This post has been edited 2 times. Last edited by hemangsarkar, Nov 26, 2016, 7:45 PM