Count the number of paths in DAG with length K - c++

I have a DAG with 2^N nodes, with values from 0 to 2^N-1. There is edge from x to y if x < y and x (xor) y = 2^p, x and y being the node values and p a non-negative integer.
Since N can be as large as 100000, generating the graph and than proceeding with the counting would take much computational time. Is there any way to count the paths with certain length K (K being the number of edges between two nodes), differently stated, is there an equation of some sort for this kind of counting?
Thanks in advance

Michael's got some good insights, but I'm not sure I follow his entire argument. Here's my solution.
Let's say N=4, K=2. So the nodes range from 0 (00002) to 15 (11112).
Now let's consider node 2 (00102). There's an edge from 2 to 3 (00112) because 2 < 3 and xor(2,3) = 1 = 20. There's also an edge from 2 to 6 because 2 < 6 and xor(2,6) = 4 = 22. And there's an edge from 2 to 10 because 2 < 10 and xor(2,10) = 8 = 23.
To generalize: for any x, consider all of the 0 bits in x. By flipping any of the 0 bits to 1, you get a number y that's larger than x and differs from x by one bit. So there's an edge from x to that y.
The number of 1 bits in x is typically called the population count of x. I'll use pop(x) to mean the population count of x.
We're dealing with N-bit numbers (when we include leading zeroes), so the number of 0 bits in x is N - pop(x).
Let's use the term “j-path” to mean a path of length j. We want to count the number of K-paths.
Every node x has N - pop(x) outgoing edges. Each of these edges is a 1-path.
Let's consider node 5 (01012). Node 5 has an edge to 7 (01112), and node 7 has an edge to 15 (11112). Node 5 also has an edge to 13 (11012), and node 13 has an edge to 15 (11112). So there are two 2-paths out of node 5: 5-7-15 and 5-13-15.
Next let's look at node 2 (00102) again. Node 2 has an edge to 3 (00112), which has edges to 7 (01112) and 11 (10112). Node 2 also has an edge to node 6 (01102), which has edges to 7 (01112) and 14 (11102). Finally, node 2 has an edge to node 10 (10102), which has edges to 11 (10112) and 14 (11102). In all, there are six 2-paths out of node 2: 2-3-7, 2-3-11, 2-6-7, 2-6-14, 2-10-11, and 2-10-14.
The pattern is that, for any node x with z bits set to zero, where z ≥ K, there are some K-paths out of x. To find a K-path out of x, you pick any K of the zero bits. Flipping those bits to 1, one by one, gives you the path. You can flip the bits in any order you want; each order gives a different path.
When you want to pick k items, in a specific order, from a set of n items, that's called an ordered sample without replacement, and there are n! / (n-k)! ways to do it. This is often written nPk, but it's easier to type P(n,k) here.
So, the nodes that have exactly 2 zero bits have P(2,2) = 2! / (2-2)! = 2 2-paths out of them. (Note that 0! = 1.) The nodes that have exactly 3 zero bits have P(3,2) = 3! / 1! = 6 2-paths out of them. The node that has exactly 4 zero bits has P(4,2)= 4! / 2! = 12 2-paths out of it. (Since I'm using N=4 for the example, there is only one node with exactly 4 zero bits, which is node 0.)
But then we need to know, how many nodes have exactly 2 zero bits? Well, when there are n items to choose from, and we want to choose k of them, and we don't care about the order of the chosen items, that's called an unordered sample without replacement, and there are n! / (k! (n-k)!) ways to do it. This is called “n choose k”, and it's usually written in a way that I can't reproduce on stack overflow, so I'll write it as C(n,k).
For our example with N=4, there are C(4,2) = 6 nodes with exactly 2 bits set to zero. These nodes are 3 (00112), 5 (01012), 6 (01102), 9 (10012), 10 (10102), and 12 (11002). Each of these nodes has P(2,2) 2-paths out of it, so that means there are C(4,2) * P(2,2) = 6 * 2 = 12 2-paths out of nodes with exactly two 0 bits.
Then there are C(4,3) = 4 nodes with exactly 3 bits set to zero. These nodes are 1 (00012), 2 (00102), 4 (01002), and 8 (10002). Each of these nodes has P(3,2) 2-paths out of it, so there are C(4,3) * P(3,2) = 4 * 6 = 24 2-paths out of nodes with exactly three 0 bits.
Finally, there is C(4,4) = 1 node with exactly 4 bits set to zero. This node has P(4,2) = 12 2-paths out of it.
So the total number of 2-paths when N=4 is C(4,2)*P(2,2) + C(4,3)*P(3,2) + C(4,4)*P(4,2) = 12 + 24 + 12 = 48.
For general N and K (where K ≤ N), the number of K-paths is the sum of C(N,z) * P(z,K) for K ≤ z ≤ N.
I can type that into Wolfram Alpha (or Mathematica) like this:
Sum[n!/(z! (n - z)!) z!/(z - k)!, {z, k, n}]
And it simplifies it to this:
2^(n-k) n! / (n-k)!

The stated problem seems to be equivalent to this one:
Consider the set of all possible binary strings of length N. Consider operation Fi that flips i-th bit from 0 to 1. For strings x & y denote |x| the number of set bits, x
It's easy to see that one can obtain y from x by a series of exactly K operations Fi if and only if (x,y) is K-admissible. Moreover, if we fix x and sum up over all y such that (x,y) is K-admissible we get (N-|x|)!
Finally, we need to sum up over all x with |x|<=(N-K). For a given choice of |x| we have N!/(N-|x|)!|x|! possible choices of x. Combine with the above and you get that for the given |x| there are N!/|x|! possible paths.
Denote |x|=M, with M from 0 to N-K, and your answer is the sum over all M of N!/M!

Related

finding the digit sum in a arthematic sequence

I have a very simple question. I will be provided with the first term of Arithmetic Progression and the common difference. I am required to give sum of digits of all numbers in between the range of L and R.Here the sum means the sum <10 that means for a number say 157, the sum of digits is 1+5+7=13 which is further 1+3=4. The range is the index of the elements. L means the Lth number of that series and L starts from 1.Here L and R can be of range 1 to 10^18. How can i find the sum of these digits for such a large range. I know the digit sum of a number n can be calculated as (n-1)%9+1. But i can't iterate over 10^18 numbers.
Example: let say First term of Arithmetic Progression is 14 and common difference 7.Then the sum of digits of all numbers between 2 and 4 will be sum of (2+1)=3 and (2+8)=(1+0)=1 and (3+5)=8 which is equal to 12
for pattern finding
current=first;
ll arr[10]={0};
while(1)// search for the pattern
{
ll dsum=(current-1)%9+1;// calculating digit sum
if(arr[dsum]!=0)
break;
arr[dsum]=ptr;// saving the value in the array by using hashing
ptr++;
current+=c_diff;
}
for sum
for(ll i=1;i<ptr;i++)
{
sum[i]=sum[i-1]+new_arr[i];
}
Since all of your numbers will be (ultimately) reduced to a single digit, you must be having repetition after certain number of terms, and, that is maximum of 9. (because 10 digits, but 0 not possible to repeat).
So, lets start with an example. Say, a=14, d=7, l=2, r=50. I've changed the value of r from your example.
So, trying to find repetition:
Our repetition array is q (say). Then, 1st term of q is 5 (since 14 = 5).
Now, next term is 21 (= 3). Since 3 is not equal to 5, we continue.
We find all terms till we get 5 again. So, q will be like this in this example:
q[] = {5,3,1,8,6,4,2,9,7} ... and then we have 5 again, so stop.
So, our repetitive pattern has 9 members. Now, find a cumulative sum array with this, which will be like:
sum[] = {5,8,9,17,23,27,29,38,45}
Now, since r=50, find sum of r terms, which will be:
(floor)(50/9) * 45 + sum[50%9]
= 5 * 45 + 23
= 248
Now, similarly, find sum of l-1 terms, (since you have to find sum in range l..r inclusive.
Sum of 1st (2-1) = 1 terms will be:
(floor)(1/9) * 45 + sum[1 % 9]
= 0 + 5
= 5
So, the answer is, 248 - 5 = 243.
well you can solve this problem by taking two arrays of elements 9 and finding the lth term element.
from the lth term find the digit sum of lth element and save it in two array respectively .
w1=a+(l-1)*d
for(i=1,j=w1;i<=9;j+=d,i++){ if(j%9==0){array1[i]=9 ;array2[i]=9;}else{array1[i]=j%9;array2[i]=j%9;}
}
now q = r-l+1
w= q/9 and e=q%9
array1[i]=array1[i]*w // in loop from i= 1 to 9
in array2[i]=0 //new loop from i=e+1 to 9
now digitsum += array1[i]+array2[i] // from a a loop i=1 to 9 and digitsum is the sum of all digit of sequence
this digit sum is solution.

Similar to subset sum [duplicate]

This problem was asked to me in Amazon interview -
Given a array of positive integers, you have to find the smallest positive integer that can not be formed from the sum of numbers from array.
Example:
Array:[4 13 2 3 1]
result= 11 { Since 11 was smallest positive number which can not be formed from the given array elements }
What i did was :
sorted the array
calculated the prefix sum
Treverse the sum array and check if next element is less than 1
greater than sum i.e. A[j]<=(sum+1). If not so then answer would
be sum+1
But this was nlog(n) solution.
Interviewer was not satisfied with this and asked a solution in less than O(n log n) time.
There's a beautiful algorithm for solving this problem in time O(n + Sort), where Sort is the amount of time required to sort the input array.
The idea behind the algorithm is to sort the array and then ask the following question: what is the smallest positive integer you cannot make using the first k elements of the array? You then scan forward through the array from left to right, updating your answer to this question, until you find the smallest number you can't make.
Here's how it works. Initially, the smallest number you can't make is 1. Then, going from left to right, do the following:
If the current number is bigger than the smallest number you can't make so far, then you know the smallest number you can't make - it's the one you've got recorded, and you're done.
Otherwise, the current number is less than or equal to the smallest number you can't make. The claim is that you can indeed make this number. Right now, you know the smallest number you can't make with the first k elements of the array (call it candidate) and are now looking at value A[k]. The number candidate - A[k] therefore must be some number that you can indeed make with the first k elements of the array, since otherwise candidate - A[k] would be a smaller number than the smallest number you allegedly can't make with the first k numbers in the array. Moreover, you can make any number in the range candidate to candidate + A[k], inclusive, because you can start with any number in the range from 1 to A[k], inclusive, and then add candidate - 1 to it. Therefore, set candidate to candidate + A[k] and increment k.
In pseudocode:
Sort(A)
candidate = 1
for i from 1 to length(A):
if A[i] > candidate: return candidate
else: candidate = candidate + A[i]
return candidate
Here's a test run on [4, 13, 2, 1, 3]. Sort the array to get [1, 2, 3, 4, 13]. Then, set candidate to 1. We then do the following:
A[1] = 1, candidate = 1:
A[1] ≤ candidate, so set candidate = candidate + A[1] = 2
A[2] = 2, candidate = 2:
A[2] ≤ candidate, so set candidate = candidate + A[2] = 4
A[3] = 3, candidate = 4:
A[3] ≤ candidate, so set candidate = candidate + A[3] = 7
A[4] = 4, candidate = 7:
A[4] ≤ candidate, so set candidate = candidate + A[4] = 11
A[5] = 13, candidate = 11:
A[5] > candidate, so return candidate (11).
So the answer is 11.
The runtime here is O(n + Sort) because outside of sorting, the runtime is O(n). You can clearly sort in O(n log n) time using heapsort, and if you know some upper bound on the numbers you can sort in time O(n log U) (where U is the maximum possible number) by using radix sort. If U is a fixed constant, (say, 109), then radix sort runs in time O(n) and this entire algorithm then runs in time O(n) as well.
Hope this helps!
Use bitvectors to accomplish this in linear time.
Start with an empty bitvector b. Then for each element k in your array, do this:
b = b | b << k | 2^(k-1)
To be clear, the i'th element is set to 1 to represent the number i, and | k is setting the k-th element to 1.
After you finish processing the array, the index of the first zero in b is your answer (counting from the right, starting at 1).
b=0
process 4: b = b | b<<4 | 1000 = 1000
process 13: b = b | b<<13 | 1000000000000 = 10001000000001000
process 2: b = b | b<<2 | 10 = 1010101000000101010
process 3: b = b | b<<3 | 100 = 1011111101000101111110
process 1: b = b | b<<1 | 1 = 11111111111001111111111
First zero: position 11.
Consider all integers in interval [2i .. 2i+1 - 1]. And suppose all integers below 2i can be formed from sum of numbers from given array. Also suppose that we already know C, which is sum of all numbers below 2i. If C >= 2i+1 - 1, every number in this interval may be represented as sum of given numbers. Otherwise we could check if interval [2i .. C + 1] contains any number from given array. And if there is no such number, C + 1 is what we searched for.
Here is a sketch of an algorithm:
For each input number, determine to which interval it belongs, and update corresponding sum: S[int_log(x)] += x.
Compute prefix sum for array S: foreach i: C[i] = C[i-1] + S[i].
Filter array C to keep only entries with values lower than next power of 2.
Scan input array once more and notice which of the intervals [2i .. C + 1] contain at least one input number: i = int_log(x) - 1; B[i] |= (x <= C[i] + 1).
Find first interval that is not filtered out on step #3 and corresponding element of B[] not set on step #4.
If it is not obvious why we can apply step 3, here is the proof. Choose any number between 2i and C, then sequentially subtract from it all the numbers below 2i in decreasing order. Eventually we get either some number less than the last subtracted number or zero. If the result is zero, just add together all the subtracted numbers and we have the representation of chosen number. If the result is non-zero and less than the last subtracted number, this result is also less than 2i, so it is "representable" and none of the subtracted numbers are used for its representation. When we add these subtracted numbers back, we have the representation of chosen number. This also suggests that instead of filtering intervals one by one we could skip several intervals at once by jumping directly to int_log of C.
Time complexity is determined by function int_log(), which is integer logarithm or index of the highest set bit in the number. If our instruction set contains integer logarithm or any its equivalent (count leading zeros, or tricks with floating point numbers), then complexity is O(n). Otherwise we could use some bit hacking to implement int_log() in O(log log U) and obtain O(n * log log U) time complexity. (Here U is largest number in the array).
If step 1 (in addition to updating the sum) will also update minimum value in given range, step 4 is not needed anymore. We could just compare C[i] to Min[i+1]. This means we need only single pass over input array. Or we could apply this algorithm not to array but to a stream of numbers.
Several examples:
Input: [ 4 13 2 3 1] [ 1 2 3 9] [ 1 1 2 9]
int_log: 2 3 1 1 0 0 1 1 3 0 0 1 3
int_log: 0 1 2 3 0 1 2 3 0 1 2 3
S: 1 5 4 13 1 5 0 9 2 2 0 9
C: 1 6 10 23 1 6 6 15 2 4 4 13
filtered(C): n n n n n n n n n n n n
number in
[2^i..C+1]: 2 4 - 2 - - 2 - -
C+1: 11 7 5
For multi-precision input numbers this approach needs O(n * log M) time and O(log M) space. Where M is largest number in the array. The same time is needed just to read all the numbers (and in the worst case we need every bit of them).
Still this result may be improved to O(n * log R) where R is the value found by this algorithm (actually, the output-sensitive variant of it). The only modification needed for this optimization is instead of processing whole numbers at once, process them digit-by-digit: first pass processes the low order bits of each number (like bits 0..63), second pass - next bits (like 64..127), etc. We could ignore all higher-order bits after result is found. Also this decreases space requirements to O(K) numbers, where K is number of bits in machine word.
If you sort the array, it will work for you. Counting sort could've done it in O(n), but if you think in a practically large scenario, range can be pretty high.
Quicksort O(n*logn) will do the work for you:
def smallestPositiveInteger(self, array):
candidate = 1
n = len(array)
array = sorted(array)
for i in range(0, n):
if array[i] <= candidate:
candidate += array[i]
else:
break
return candidate

To find the min and max after addition and subtraction from a range of numbers

I am having a Algorithm question, in which numbers are been given from 1 to N and a number of operations are to be performed and then min/max has to be found among them.
Two operations - Addition and subtraction
and operations are in the form a b c d , where a is the operation to be performed,b is the starting number and c is the ending number and d is the number to be added/subtracted
for example
suppose numbers are 1 to N
and
N =5
1 2 3 4 5
We perform operations as
1 2 4 5
2 1 3 4
1 4 5 6
By these operations we will have numbers from 1 to N as
1 7 8 9 5
-3 3 4 9 5
-3 3 4 15 11
So the maximum is 15 and min is -3
My Approach:
I have taken the lower limit and upper limit of the numbers in this case it is 1 and 5 only stored in an array and applied the operations, and then had found the minimum and maximum.
Could there be any better approach?
I will assume that all update (addition/subtraction) operations happen before finding max/min. I don't have a good solution for update and min/max operations mixing together.
You can use a plain array, where the value at index i of the array is the difference between the index i and index (i - 1) of the original array. This makes the sum from index 0 to index i of our array to be the value at index i of the original array.
Subtraction is addition with the negated number, so they can be treated similarly. When we need to add k to the original array from index i to index j, we will add k to index i of our array, and subtract k to index (j + 1) of our array. This takes O(1) time per update.
You can find the min/max of the original array by accumulating summing the values and record the max/min values. This takes O(n) time per operation. I assume this is done once for the whole array.
Pseudocode:
a[N] // Original array
d[N] // Difference array
// Initialization
d[0] = a[0]
for (i = 1 to N-1)
d[i] = a[i] - a[i - 1]
// Addition (subtraction is similar)
add(from_idx, to_idx, amount) {
d[from_idx] += amount
d[to_idx + 1] -= amount
}
// Find max/min for the WHOLE array after add/subtract
current = max = min = d[0];
for (i = 1 to N - 1) {
current += d[i]; // Sum from d[0] to d[i] is a[i]
max = MAX(max, current);
min = MIN(min, current);
}
Generally there is no "best way" to find the min/max in the performance point of view because it depends on how this application will be used.
-Finding the max and min in a list needs O(n) Time, so if you want to run many (many in the context of the input) operations, your approach to find the min/max after all the operations took place is fine.
-But if the list will hold many elements and you don’t want to run that many operations, you better check each result of the op if its a new max/min and update if necessary.

graphs divisibility

Given a simple undirected graph containing N vertices numbered 1 to N, each vertex containing a digit from {1,2,..7}. Starting at the vertex 1 with an empty string S, we travel through some vertices (with no limitations) to the vertex N. For every vertex on the way, we add the respective digit to the right of the string S. At last we get S as a decimal integer. You are requested to find such a way satisfying S is divisible by all of its digits, and the sum of digits of S must be as small as possible.
Input
There are several test cases (fifteen at most), each formed as follows:
The first line contains a positive integer N (N ≤ 100).
The second line contains N digits (separated by spaces), the i-th digit is the value of the i-th vertex.
N last lines, each contains N values of {0, 1} (separated by spaces), the j-th value of the i-th line is equal to 1 if there is an edge connecting two vertices (i, j), otherwise 0.
The input is ended with N = 0.
Output
For each test case, output on a line the minimum sum of digits found, or -1 if there's no solution.
example
Input:
4
1 2 1 4
0 1 1 1
1 0 0 1
1 0 0 1
1 1 1 0
Output:
7
please guide me
there can be self loops and cycles such that node 1 and node N can be visted any number of times
If given graph is transformed to some other graph, where cycles are not allowed, this problem can be solved with Dijkstra's algorithm.
To do this, let's start with string divisibility by 7. Look at this sequence: 1, 10, 100, ... (mod 7). Since 7 is a prime number, 107-1 = 1 (mod 7) because of Fermat's little theorem. Which means 1, 10, 100, ... (mod 7) sequence is periodic and period is 6. This will be used to transform the graph and also this allows to recursively compute Sn (mod 7) using Sn-1 (mod 7): Sn = Sn-1 + 10n%6 * n_th_digit (mod 7).
It's necessary to start shortest path search from node N because this path may be ended at one of the several nodes of the transformed graph. Also this allows to determine quickly (using first 2 nodes of the path), if it is allowed to visit node "5", node"4", and other "even" nodes.
Algorithm's open set (the priority queue) should contain the priority itself (sum of digits) as long as 3 additional bits and 3 remainders: is "4" allowed, is "3" visited, is "7" visited, S % 3, S % 7, and S.length % 6.
Graph should be transformed as follows. Each vertex is expanded to 3 vertexes, one is allowed only for S%3==0, others - for S%3==1 and S%3==2. Then each vertex is expanded to 7 (for S%7), and then each vertex is expanded to 6 (for S.length % 6). It is possible to fit all these expansions to the original graph: just add a 3D array (size 3*7*6) of back-pointers to each node. While searching for the shortest path, the non-empty back-pointers determine algorithm's closed set (they disallow cycles). When shortest path is found, back-pointers allow to reconstruct the sequence of nodes in this path. And the moment when shortest path is found is determined by visiting node 1 with (node_3_not_visited || S%3==0) && (node_7_not_visited || S%7==0).
First mathematically find the LCM of the numbers given in the set.
lemme paraphrase the scenario .... given a set of numbers... find the LCM then traverse the vetices in such a way that the their path makes the number .Since its LCM it is number whose sum is mininum
For set {0,1,2,3,4} LCM is 12 so travers from 1 to 2
for set {0,1,2,3,4,5,6,7} LCM is 420..(I think i am right)
Use the A* search algorithm, where the "cost" is the sum of the digits, and divisibility determines which edges you can traverse.

PROJECT EULER #29

Well, after solving this problem by naive STL set,I was reading the forum entries,there I find this entry :
#include <iostream>
#include <cmath>
#define MAX 100
using namespace std;
int main(){
int res=(MAX-1)*(MAX-1);
for(int i=2;i<MAX;i++)
for(int j=i*i;j<=MAX;j=j*i)
res = res-int(MAX*(log(i)/log(j)))+1;
cout<<res<<endl;
return 0;
}
The author's explanation :
Maximum will be 99*99. I subtracted occurrences of those numbers which are powers of some lower numbers (2-100): -
For example: -
4^2,4^3,4^4 (i.e. 3 should be subtracted) as they will be duplicates from lower number powers as in 2^4,2^6,2^8
This program is giving correct answer check here but I am unable to get the implemented logic,to be precise I am not getting how the duplicates are determined. Could somebody help ?
I may be missing something, but it seems to me this program gives the wrong answer. It's off by one. If I set MAX to 10, it's off by two.
I have read that some players like to produce approximate answers and then dictionary-attack the Project Euler servers to brute-force the problem. Other players consider that rather against the spirit of the thing.
Anyway—an algorithm like this (starting with N*M and eliminating duplicates) is the right way to tackle the problem, but as written this code doesn't make much sense to me. Note that in any case int(MAX*(log(i)/log(j))) is very sensitive to rounding error; but even if you eliminate that source of error by using integer arithmetic, the program still gives the wrong answer.
EDIT: How can we (correctly) count the duplicates?
First you must understand that two numbers are only the same if they have the same prime factorization. So there are only going to be duplicates a1b1 = a2b2 when a1 and a2 are distinct integer powers of the same integer, which I'll call x. For example,
97 = 314; this is possible because 9 and 3 are both powers of 3.
86 = 49; this is possible because 8 and 4 are both powers of 2.
So we have established that for all duplicates, a1 = xe1 and a2 = xe2 for some integers x, e1, and e1.
Then with a little algebra,
a1b1 = a2b2
xe1b1 = xe2b2
e1b1 = e2b2
Going back to the earlier examples,
97 = 314 because 2×7 = 1×14.
86 = 49 because 3×6 = 2×9.
So to find all duplicates for any given x, you only need to find duplicates for the simpler expression eb where 2 ≤ xe ≤ 100 and 2 ≤ b ≤ 100.
Here is a picture of that simpler problem, for x=3 and b ranging only from 2 to 10. I've marked two places where there are duplicates.
e=1 a=3 *********
e=2 a=9 * * * * * * * * *
e=3 a=27 * * * * * * * * *
e=4 a=81 * * * * * * * * *
| |
1*8 = 2*4 = 4*2 3*8 = 4*6
3^8 = 9^4 = 81^2 27^8 = 81^6
And here are the duplicates:
e=1 a=3 *********
e=2 a=9 x x x x * * * * *
e=3 a=27 x x x * x * * * *
e=4 a=81 x x x x x * * * *
The C++ program you found is trying to count them by visiting each pair of overlapping rows i and j, and calculating how much of row i overlaps row j. But again, unless I'm missing something, the program seems hopelessly imprecise. And it misses some pairs of rows entirely (you never have i=9 and j=27, or i=27 and j=81).
first, it sets res to 99*99 at line 6, because MAX was defined as 100. Then it enters a loop, with the condition that i is smaller than MAX. then it enters this pseudocode loop
int i;
int j;
int x=2;
for( j = i2; j <= MAX , j = ix)
{
res = res- (MAX* ( jlog(i) )+1;
x++;
}
sorry 'bout the not using <pre><code> above; but if I did I could not use <sup>
Please note log(a)/log(x) is the same as xlog(a)
comments on question because <sup> does not work there:
2log(2) = 1 because 21 = 2
2log(4) = 2 because 22 = 2
log(x) == 10log(x)
log(10) = 1
glog(x) = y => gy = x
Well, the question involves ways to combine two numbers chosen from a range. There are 99 possible numbers, so the number of combinations is 99 * 99, with possible duplicates. His basic algorithm here is to figure out how many duplicates are present, and subtract that value from the maximum.
As for counting duplicates, it might help intuitively to think of the numbers in terms of their prime factors. Raising a number to an integer power means multiplying it by itself; so, represented as a list of primes, this is equivalent to simply concatenating the lists. For instance, 6 is {2, 3}, so 6^3 would be {2, 2, 2, 3, 3, 3}. Note that if you count how many times each prime appears in the list, x^n will always have the same proportions as x, for instance 6^n will have an equal quantity of 2's and 3's. So, any two numbers in the range with the same proportion between primes must both be powers of some number.
So, in the full list, each distinct proportion of prime factors will appear repeatedly as x^2, x^3, x^4..., (x^3)^2, (x^3)^4..., (x^4)^2..., etc., where x is the smallest number with that proportion; more precisely, (x^m)^n where (x^m) <= 100 and 2 <= n <= 100. Since (x^m)^n is equal to x^(mn), counting duplicates amounts to counting the ways that x^(mn) can also be <= 100.
There are (at least) two ways to approach this problem. One is to start your count of distinct values at 0, and add one for each calculated value that hasn't been seen before. The other way is to calculate the maximum number of values, and then subtract one for each duplicate.
The poster is attempting the second methed. a can range from 2 to 100 for 99 values, as can b, so there are 99 * 99 produced values. The poster then attempts to subtract the duplicate values to get the correct answer.
Edit: However, the poster has written an incorrect algorithm.
For instance, setting MAX = 8 or 9. For 8 it should give 44 but it gives 45. For 9 it should give 54 but gives 56. Either they lucked out and happened across an algorithm that gives the correct answer for some inputs, or they reverse-engineered an algorithm that worked when MAX = 100 but not for all other values.