Stuck on seemingly trivial algorithm task - algorithm

Being given a positive integer n for the input, output a list of
consecutive positive integers which, summed up, will make up this
number or IMPOSSIBLE if it can't be done. In case of multiple possible
anwers, output any with the least summands.
It's a problem from CERC competition held a few days ago and while I can solve it using some weird theories I made up, I have no idea how to tackle it elegantly.
I know that no number in the form 2^i where i is a non-negitve integer can be made and that any odd number can be presented in a two-summand form of floor(n/2)+(floor(n/2)+1) but when it comes to the even numbers, I'm clueless about some elegant solution and I heard it can be solved with some one formula. I thought about dividing the number till we're left with something odd and then trying to put the summands of this odd number in the center of the even one or trying to put the number divided by the odd one in the middle but it doesn't sound right, not to mention elegant. It was solved in under 10 minutes by some teams so the route I mention above is almost certainly wrong and I'm overthinking it way too much.
What would be the best and fastest way to solve this?

The sum of a set of positive integers from m to n is
n(n + 1)/2 - m(m - 1)/2
(ie. sum of numbers from 1 to n less the sum from 1 to m - 1)
which is
((n^2 - m^2) +(n + m))/2
which is
(n + m)( n - m + 1)/2
So if you need to make that equal x for some x
2x = (n + m)(n - m + 1)
So look for factors of 2x and see which fit that pattern

Ookay, since #Pokechu22 was interested in how my team solved it (and it seems even one more person was, judging by the upvote next to the message :)), here it goes. It works, it fit the time limit but beware that it's kinda twisted and even after those few days I have serious doubts if I still remember how it worked :D Let's get to it.
So first, we if two scenarios - if n is 1, output Impossible and if n is odd, output floor(n/2)+(floor(n/2)+1). Now for the real fun:
We know that any even number has to be a sum of at least three consecutive integers cause for it to be a sum of two, we'd need two consecutive odd or two consecutive even numbers and that's impossible. Thus, we derived a sequence of sequences and their corresponding sums in the form of:
Length | Sequence | Sum
3 1-2-3 6
4 0-1-2-3 6
5 0-1-2-3-4 10
6 IMPOSSIBLE N/A
7 1-2-3-4-5-6-7 28
8 0-1-2-3-4-5-6-7 28
9 0-1-2-3-4-5-6-7-8 36
10 IMPOSSIBLE N/A
...and so on
As it turns out, every possible answer sequence is just one of those, shifted to the right by some number. To find out what the number is, for each element sum_i of the table above, we check if n-sum_i is divisible by length_i. If it is, we have our solution cause all that's left is to shift the given sequence by that many places (in other words, add (n-sum_i)/length_i to every element of sequence_i). In case of using the sequence with 0 at the beginning, we also have to remember to shift it one additional space right (start at the next integer). Thus, we arrive at a code looking like this:
bool shouldBeShifted = false;
bool foundSolution = false;
long long sum_i = 6, length_i = 3;
while(n - sum_i >= 0)
{
long long tmp = n - sum_i;
if(tmp % length_i == 0) {foundSolution = true; break;}
++length_i;
if(tmp % length_i == 0) {foundSolution = true; shouldBeShifted = true; break;}
sum_i += length_i;
++length_i;
tmp = n - sum_i;
if(tmp % length_i == 0) {foundSolution = true; break;}
length_i += 2;
sum_i = ((3 * length_i) - 3) + sum_i;
shouldBeShifted = false;
}
If after the loop foundSolution turned out to be true, we've found a solution of length length_i which starts at number (n / length_i) - (length_i / 2) + (shouldBeShifted ? 1 : 0) :) Believe it or not, it does work and finds optimal solution... :D

Related

Check if number is multiple of 5 in most efficient way

Info
Hi everyone
I was searching an efficient way to check if a number is multiple of 5. So I searched on google and found this solution on geeksforgeeks.org.
There were 3 solutions of my problem.
First solution was to subtract 5 until reaching zero,
Second solution was to convert the number to string and check last character to be 5 or 0,
Third solution was by doing some interesting operations on bitwise level.
I'm interested in third solution as I can fully understand the first and the second.
Here's the code from geeksforgeeks.
bool isMultipleof5(int n)
{
// If n is a multiple of 5 then we
// make sure that last digit of n is 0
if ( (n & 1) == 1 )
n <<= 1;
float x = n;
x = ( (int)(x * 0.1) ) * 10;
// If last digit of n is 0 then n
// will be equal to (int)x
if ( (int)x == n )
return true;
return false;
}
I understand only some parts of the logic. I haven't even tested this code. So I need to understand it to use freely.
As said in mentioned article this function is multiplying number by 2 if last bit is set and then checking last bit to be 0 and returns true in that case. But after checking binary representations of numbers I got confused as last bit is 1 in case of any odd number and last bit is 0 in case of any even number. So...
Actual question is
What's the logic of this function?
Any answer is appreciated!
Thanks for all!
The most straightforward way to check if a number is a multiple of 5 is to simply
if (n % 5 == 0) {
// logic...
}
What the bit manipulation code does is:
If the number is odd, multiply it by two. Notice that for multiples of 5, the ones digit will end in either 0 or 5, and doubling the number will make it end in 0.
We create a number x that is set to n, but with a ones digit set to 0. (We do this by multiplying n by 0.1, which removes the ones digit, and then multiply by 10 in order to add a 0, which has a total effect of just changing the ones digit to 0).
We know that originally, if n was a multiple of 5, it would have a ones digit of 0 after step 1. So we check if x is equal to it, and if so, then we can say n was a multiple of 5.

four-square sum representation for integers upto N

Lagrange's four-square theorem proves that any natural number can be written as the sum of four square numbers. What I need is to find any one way to write a natural number x as sum of four square numbers for all 0 <= x <= N for any given upper limit N.
What I have done so far is find two-square sum representation for all the numbers <= N for which it is possible to find one, and saved them in an array called two_square_div. Then I used a greedy approach like following:
last_two_square_sum = 0
for num in 0..N
if num can be written as sum of two square
last_two_square_sum = num
other_last_two_square_sum = num - last_two_square_sum
four_square_div[num] = (two_square_div[last_two_square_sum], two_square_div[other_last_two_square_sum]
But this approach does not work for numbers like 23, for which last_two_square_sum = 20 other_last_two_square_sum = 3. But 3 can not be written as sum of two squares so this method fails.
So could anybody provide a correct O(N) solution or any helpful hint? Thank you.
Your algorithm should make more than one attempt (if it already does, then the exit condition must be improved).
23 can be written as 3 + 20, yes; but 3 is not a decomposable of order two and can't lead to a solution.
So you go on: next you try 4 + 19, and this time it's 19 that is rejected. Next you try 5, so 23-5 is 18, and 5 is 12 + 22 while 18 is 32 + 32.
(Of course this is not O(N) at all).
It is not clear to me how you arrive at 20 and not accept previous solutions; try posting the whole of the code.
Also, try asking on Math StackExchange.

Algorithm for calculate all difference values from a large list

​I have a question that now I have a list of 3 million records and I want get all difference values between every two records. A simple nested loop may take forever. Could anyone suggest me any algorithm which is capable of handling this problem?
If you want to calculate the mean of all absolute differences and your timestamps are sorted, you just need one loop:
t[i] <= t[i + 1] --> abs(t[i] - t[j]) = t[j] - t[i] for i < j
That is, there is a summand with positive sign and another summand with a negative sign for each of the N timestamp differences. Let's look at an example with 4 timestamps:
sum = (t[3] - t[2]) + (t[3] - t[1]) + (t[3] - t[0])
+ (t[2] - t[1]) + (t[2] - t[0])
+ (t[1] - t[0])
Here, t[3] is always added, t[2] is added twice and subtracted once, t[1] is added once and subtracted twice and finally the lowest value, t[0] is always subtracted.
Ore, more general: The first timestamp, i.e. the one with the lowest value, has always the negative sign, N - 1 times. The second has N - 2 times negative signs and a positive sign once, namely when comparing the the first timestamp. The third has N - 3 times a negative sign and a positive sign twice.
So your loop goes like this:
sum = 0;
for i = 0 to N:
sum = sum + (2*i - N + 1) * t[i]
where i is a zero-based index and N an exclusive upper bound, C-style. To get the average, divide by (N - 1) * N / 2.
If your array isn't sorted, you must sort it first, which usually has better performance than quadratic time, so you should be better off than with a nested loop.
One thing that might occur is that by summing up large values, you hit the limits of your data type. You could try to fix that by halving your loop and start summing from both ends in the hope that the differences about cancel themselves out. Alternatively you could already divide by the total number of differences inside the loop, possibly introducing some nasty floating-point round-off errors.
You could parallelise the problem by splitting the file into, say 8, chunks and processing them all at the same time and making the most of those expensive Intel iCores you paid for....
Use the split command to generate the lists.
#!/bin/bash
split -l 375000 yourfile sublist # split into lumps of 375,000 subfiles called sublist*
for f in sublist* # for all list* files
do
# Start a background process to work on one list
echo start processing file $f in background &
done
wait # till all are finished

Generating all integers n which n&m==n(m is a given integers) effeciently in C

& is bit AND in C.
Example:
m= 21(10101)
The result:
0 16 4 1 20 5 17 21
My code:
for(int i=0;i<=m;i++)
if ((i&m)==i) printf("%d ",i);
This will be very slow when m is large.
How to find the result quickly (when answer is very few, such as m=2^30)?
i = 0
repeat
print(i)
i = (i + (NOT m) + 1) AND m
until i == 0
UPD :
A bit simpler code:
i = 0
repeat
print(i)
i = (i - 1) AND m
until i == 0
The accepted answer is correct, but a bit sparse on detail, so here's why it works
Observe that the set { n | n & m == n } is the set of all n such that the bits in n are a subset of those in m. If all those bits were in a group starting at the least significant bit, they could be generated by simply counting from 0 to m.
But they're not necessarily grouped thus, there may be empty spaces between the bits. These spaces should be skipped, and how do you make the carry from the incrementing skip those bits?
Well you can make the carry propagate (not exactly skip) through those bits by making them 1. That leaves some garbage in those bits though, which has to be cleared out.
So, first set the bits in the gaps: i | ~m (written equivalently as i ^ ~m or i + ~m because the bits in ~m are guaranteed to not overlap with any bits in i).
Then do the increment (+1) and then throw away any garbage left in the gaps: & m.
In total: ((i | ~m) + 1) & m.
For the new code, observe that making a borrow from a subtraction propagate through the gaps is easier, because in order for it to propagate the gap should be filled with zeroes, which it already is. The only issue, then, is that some garbage may be left behind in the gaps, which should be cleared out with & m, giving, in total, (i - 1) & m.
One line code:
for(i=m;i;i=(i-1)&m) printf("%d ",i);printf("0");

(ProjectEuler) Sum Combinations

From ProjectEuler.net:
Prob 76: How many different ways can one hundred be written as a sum of at least two positive integers?
I have no idea how to start this...any points in the right direction or help? I'm not looking for how to do it but some hints on how to do it.
For example 5 can be written like:
4 + 1
3 + 2
3 + 1 + 1
2 + 2 + 1
2 + 1 + 1 + 1
1 + 1 + 1 + 1 + 1
So 6 possibilities total.
Partition Numbers (or Partition Functions) are the key to this one.
Problems like these are usually easier if you start at the bottom and work your way up to see if you can detect any patterns.
P(1) = 1 = {1}
P(2) = 2 = {[2], [1 + 1]}
P(3) = 3 = {[3], [2 + 1], [1 + 1 + 1]}
P(4) = 5 = {[4], [3 + 1], [2 + 2], [2 + 1 + 1], [1 + 1 + 1 + 1]}
P(5) = 7 ...
P(6) = 11 ...
P(7) = 15 ...
P(8) = 22 ...
P(9) = 30 ...
Hint: See if you can build P(N) up from some combination of the results prior to P(N).
The solution can be found using a chopping algorithm.
Use for example the 6. Then we have:
6
5+1
4+2
3+3
but we are not finished yet.
If we take the 5+1, and consider the +1 part as finished, because all other ending combinations are handled by the 4+2 and 3+3. So we need to apply the same trick to the 5.
4+1+1
3+2+1
And we can continue. But not mindlessly. Because for example 4+2 produces 3+1+2 and 2+2+2. But we don't want the 3+1+2 because we will have a 3+2+1. So we only use all productions of 4 where the lowest number is greater or equal than 2.
6
5+1
4+1+1
3+1+1+1
2+1+1+1+1
1+1+1+1+1+1
2+2+1+1
3+2+1
4+2
2+2+2
3+3
Next step is to put this in an algorithm.
Ok we need a recursive function that takes two parameters. The number to be chopped and the minimal value:
func CountCombinations(Number, Minimal)
temp = 1
if Number<=1 then return 1
for i = 1 to Floor(Number/2)
if i>=Minimal then
temp := temp + CountCombinations(Number-i, i)
end for
return temp
end func
To check the algorithm:
C(6,1) = 1 + C(5,1) + C(4,2) + C(3,3) = 11, which is correct.
C(5,1) = 1 + C(4,1) + C(3,2) = 7
C(4,1) = 1 + C(3,1) + C(2,2) = 5
C(3,1) = 1 + C(2,1) = 3
C(2,1) = 1 + C(1,1) = 2
C(1,1) = 1
C(2,2) = 1
C(3,2) = 1
C(4,2) = 1 + C(2,2) = 2
C(3,3) = 1
By the way, the number of combinations of 100:
CC(100) = 190569292
CC(100) = 190569291 (if we don't take into account 100 + 0)
A good way to approach these is not get fixated on the '100' but try to consider what the difference between totalling for a sum n and n+1 would be, by looking for patterns as n increases 1,2,3....
I'd have a go now but I have work to do :)
Like most problems in Project Euler with big numbers, the best way to think about them is not to get stumped with that huge upper bound, and think of the problem in smaller terms, and gradually work your way up. Maybe, on the way you'll recognize a pattern, or learn enough to get you to the answer easily.
The only other hint I think I can give you without spoiling your epiphany is the word 'partition'.
Once you've figured that out, you'll have it in no time :)
one approach is to think recursive function: find permutations of a numeric series drawn from the positive integers (duplicates allowed) that add up to 100
the zero is 1, i.e. for the number 1 there are zero solutions
the unit is 2, i.e for the number 2 there is only one solution
another approach is to think generative function: start with the zero and find permutation series up to the target, keeping a map/hash or the intermediate values and counts
you can iterate up from 1, or recurse down from 100; you'll get the same answer either way. At each point you could (for a naive solution) generate all permutations of the series of positive integers counting up to the target number minus 1, and count only those that add up to the target number
good luck!
Notice: My maths is a bit rusty but hopefully this will help...
You are going well with your break down of the problem.
Think Generally:
A number n can be written as (n-1)+1 or (n-2)+2
You generalise this to (n-m)+m
Remember that the above also applies to all numbers (including m)
So the idea is to find the first set (lets say 5 = (5-1)+1) and then treat (5-1) as a new n...5 = 4 +1...5 = ((4-1)+1)+1. The once that is exhausted begin again on 5 = 3 + 2....which becomes 5 = ((3-1)+1)+2 ....= 2+1+2....breaking down each one as you go along.
Many math problems can be solved by induction.
You know the answer for a specific value, and you can find the answer for every value, if you find something that link n with n+1.
For example in your case you know that the answer for How many different ways can one be written as a sum of at least two positive integers? is just 1.
What do I mean with the link between n and n+1? Well I mean exactly that you must find a formula that, provide you know the answer for n, you will find the answer for n+1. Then, calling recursively that formula, you'll know the answer and you've done (note: this is just the mathematical part of it, in real life you might find that this approach would gave you something too slow to be practical, so you've not done yet - in this case I think you will be done).
Now, suppose that you know n can be written as a sum of at least two positive integers? in k different ways, one of which would be:
n=a1+a2+a3+...am (this sum has m terms)
What can you say about n+1? Since you would like just hints I'm not writing the solution here, but just what follows. Surely you have the same k different ways, but in each of them there will be the +1 term, one of which would be:
n+1=a1+a2+a3+...am+1 (this sum has m+1 terms)
Then, of course, you will have other k possibilities, such those in which the last term of each sum is not the same, but it will be increased by one, like:
n+1=a1+a2+a3+...(am+1) (this sum has m terms)
Thus there are at least 2k ways of writing n+1 as a sum of at least two positive integers. Well, there are other ones. Find it out, if you can :-)
And enjoy :-))

Resources