My solution exceeds the time limit and I can't come up with a faster solution, still very much a beginner. How can I improve it?
The problem:
A perfect ICPC team is made up of at least 1 mathematician and 1 programmer and it must have 3 members. You have the number of mathematicians, programmers and students that have no specialization. What is the maximum number of perfect teams you can make? C students are programmers, M students are mathematicians and X don't have a specialization.
Example input:
1 1 1
Example output:
1
Example input:
3 6 0
Example output:
3
Example input:
10 1 10
Example output:
1
My solution:
cmx = [int(x) for x in input().split()]
i = 0
while 0 not in cmx:
cmx[0] -= 1
cmx[1] -= 1
cmx[2] -= 1
i += 1
if cmx[0] != 0 and cmx[1] != 0 and cmx[2] == 0:
while sum(cmx) >= 3 and cmx[0] != 0 and cmx[1] != 0:
if cmx[0] >= cmx[1]:
cmx[0] -= 2
cmx[1] -= 1
i += 1
elif cmx[0] < cmx[1]:
cmx[0] -= 1
cmx[1] -= 2
i += 1
print(i)
Assume that M ≤ C. (Proof works identically if C ≤ M). How many teams can I make. It's clear that if M + C + X ≥ 3M, then I can easily make M teams. (Every team has a mathematician, a programmer, and either a second programmer or a "none".) And I can't make more than M teams. If M + C + X < 3M, then the most I can have is (M + C + X) / 3 teams, and again you make them the same way, since you have sufficient mathematicians and programmers.
The proof works identically if C ≤ M.
So min(M, C, (M + C + X) // 3). As stated above.
A simpler way of looking at it is that C, M, and (C + M + X)//3 are each, independently, an upper bound on the number of teams that you can form. You just have to show the smallest of these three upper bounds is, in fact, a reachable value.
Related
for i in range(0,x):
for j in range(0,y):
if (i+j)%2 == 0:
Think of something like tossing two dices at the same time and finding if the sum on the dices is an even number but here's the catch, a dice has 6 sides but here the two can have any number of sizes, equal and not equal even!
Can anyone suggest how to merge it under one loop because I can't think of any?
based on Python combine two for loops, you can merge two for loops in a single line by importing itertools as below:
import itertools
for i, j in itertools.product(range(0,x), range(0,y)):
if (i+j)%2 == 0:
You can't get rid of the nested loop (you could hide it, like by using itertool.product, but it would still be executed somewhere, and the complexity would still be O(x * y)) but you can get rid of the condition, if you only need to generate the values of j that satisfy it, by adapting the range for j.
This way, you'll have about twice as less loops by avoiding the useless ones.
for i in range(0,x):
for j in range(i%2,y, 2):
print(i, j, i+j)
Output:
0 0 0
0 2 2
1 1 2
1 3 4
2 0 2
2 2 4
For me its much cleaner to leave it as two loops. Its much more readable and easier to understand whats happening. However you could essentially do x * y then use divmod to calculate i and j
x = 2
y = 3
for i in range(0,x):
for j in range(0,y):
print(i, j, i+j)
print("###")
for r in range(x*y):
i, j = divmod(r, y)
print(i, j, i + j)
OUTPUT
0 0 0
0 1 1
0 2 2
1 0 1
1 1 2
1 2 3
###
0 0 0
0 1 1
0 2 2
1 0 1
1 1 2
1 2 3
So I wrote a piece of code in pycharm
to solve this problem:
pick any 5 positive integers that add up to 100
and by addition,subtraction or just using one of the five values
you should be able to make every number up to 100
for example
1,22,2,3,4
for 1 I could give in 1
for 2 i could give in 2
so on
for 21 I could give 22 - 1
for 25 I could give (22 + 2) - 1
li = [1, 1, 1, 1, 1]
lists_of_li_that_pass_T1 = []
while True:
if sum(li) == 100:
list_of_li_that_pass_T1.append(li)
if li[-1] != 100:
li[-1] += 1
else:
li[-1] = 1
if li[-2] != 100:
li[-2] += 1
else:
li[-2] = 1
if li[-3] != 100:
li[-3] += 1
else:
li[-3] = 1
if li[-4] != 100:
li[-4] += 1
else:
li[-4] = 1
if li[-5] != 100:
li[-5] += 1
else:
break
else:
if li[-1] != 100:
li[-1] += 1
else:
li[-1] = 1
if li[-2] != 100:
li[-2] += 1
else:
li[-2] = 1
if li[-3] != 100:
li[-3] += 1
else:
li[-3] = 1
if li[-4] != 100:
li[-4] += 1
else:
li[-4] = 1
if li[-5] != 100:
li[-5] += 1
else:
break
this should give me all the number combinations that add up to 100 out of the total 1*10 ** 10
but its not working please help me fix it so it prints all of the sets of integers
I also can't think of what I would do next to get the perfect sets that solve the problem
After #JohnY comments, I assume that the question is:
Find a set of 5 integers meeting the following requirements:
their sum is 100
any number in the [1, 100] range can be constructed using at most once the elements of the set and only additions and substractions
A brute force way is certainly possible, but proving that any number can be constructed that way would be tedious. But a divide and conquer strategy is possible: to construct all numbers up to n with a set of m numbers u0..., um-1, it is enough to build all numbers up to (n+2)/3 with u0..., um-2 and use um-1 = 2*n/3. Any number in the ((n+2)/3, um-1) range can be written as um-1-x with x in the [1, (n+2)/3] range, and any number in the (um-1, n] range as um-1+y with y in the same low range.
So we can use here u4 = 66 and find a way to build numbers up to 34 with 4 numbers.
Let us iterate: u3 = 24 and build numbers up to 12 with 3 numbers.
One more step u2 = 8 and build numbers up to 4 with 2 numbers.
Ok: u0 = 1 and u1 = 3 give immediately:
1 = u0
2 = 3 - 1 = u1 - u0
3 = u1
4 = 3 + 1 = u1 + u0
Done.
Mathematical disgression:
In fact u0 = 1 and u1 = 3 can build all numbers up to 4, so we can use u2 = 9 to build all numbers up to 9+4 = 13. We can prove easily that the sequence ui = 3i verifies sum(ui for i in [0, m-1]) = 1 + 3 + ... + 3m-1 = (3m - 1)/(3 - 1) = (um - 1) / 2.
So we could use u0=1, u1=3, u2=9, u3=27 to build all numbers up to 40, and finally set u4 = 60.
In fact, u0 and u1 can only be 1 and 3 and u2 can be 8 or 9. Then if u2 == 8, u3 can be in the [22, 25] range, and if u2 == 9, u3 can be in the [21, 27] range. The high limit is given by the 3i sequence, and the low limit is given by the requirement to build numbers up to 12 with 3 numbers, and up to 34 with 4 ones.
No code was used, but I think that way much quicker and less error prone. It is now possible to use Python to show that all numbers up to 100 can be constructed from one of those sets using the divide and conquer strategy.
The Problem Statement:
Sanjay is addicted to alcohol. Every night he drinks 4 bottles of vodka. He is going to his home. At first, he takes a step forward (which is 5m) but beacuse he is drunk, after his each step in forward direction, his body gets imbalanced and he takes a step backward (which is 3m).
Each step takes 1 min to complete. The distance from the bar to home is n metres. Calculate the time taken by him to reach his home.
Input Format:
single line containing one integer n.
Constraints:
0 <= n < 10^18
Output Format
single integer describing the time taken by him to reach home.
from math import *
n = int(input())
x = 0
m = 0
n = n % 1000000007
n = n % 1000000007
while x < n:
x += 5
m += 1
if x >= n:
break
x -= 3
m += 1
print(m)
But the time limit is exceeding in the last test case i.e. for n = 10^18 like numbers
Sample Input 0
11
Sample Output 0
7
The time taken is simply n/2 * 2
He advances 2 meters each "cycle" 5 forward 3 back
So we see how many "cycles" go into n (n / 2m) this will result
In the number of "cycles" taken to reach his house
Then we simply multiply by the amount of time taken per cycle (2 minutes)
to get the total time taken (t = n/2 * 2).
Try reducing the problem. Let time_taken(dist) be the function that tells us how long it takes to get home. Then the following hold:
time_taken(1) == 1
time_taken(2) == 1
time_taken(3) == 1
time_taken(4) == 1
time_taken(5) == 1
time_taken(6) == 1 * 2 + time_taken(4) (since 5-3 = 2)
== 1 * 2 + 1
time_taken(7) == 1 * 2 + time_taken(5)
== 1 * 2 + 1
time_taken(11) == 1 * 2 + time_taken(9)
== 2 * 2 + time_taken(7)
== 3 * 2 + time_taken(5)
== 3 * 2 + 1
time_taken(26) == 1 * 2 + time_taken(24)
== 2 * 2 + time_taken(22)
== ...
== 11 * 2 + time_taken(4)
== 11 * 2 + 1
if n > 5:
time_taken(n) == 1 * 2 + time_taken(n - 2)
== 2 * 2 + time_taken(n - 4)
== ...
== (formula here) * 2 + time_taken(4 or 5)
I need to make a quick algorithm(I already made a slow one) which will find the number of all possible values from two ranges of integer numbers (ranges can intersect or not) which sum will be the given number
I can represent it like an equation: z = x + y
where z is a known number and equals x plus y
z can be any number between 0 and 10^18
x belongs to a range of integer numbers [a..b], where 0 <= a <= b <= 10^18 and
the difference between the consecutive numbers is 1
y belongs to a range of integer numbers [c..d], where 0 <= c <= d <= 10^18 and
the difference between the consecutive numbers is 1
so I need to find the number(not their exact values) of all the possible variations of x and y from two sets of numbers which sum will be z
Example:
z = 5
first set: a = 1, b = 5(it means the set consists of 1,2,3,4,5)
second set: c = 1, b = 5
then the answer is 4, because all possible combinations are:
x = 4, y = 1
x = 3, y = 2
x = 2, y = 3
x = 1, y = 4
because theirs sums are 5's
The compulsory condition for an algrorithm is to work faster than 1 second
The following code works fine but only with numbers lesser than 1000000. It starts to work much slower with big numbers
with open(r"input.txt") as f:
n = int(f.readline()) # the given number
a = int(f.readline()) # the start position of the first set
b = int(f.readline()) # the end position of the first set
c = int(f.readline()) # the start position of the second set
d = int(f.readline()) # the end position of the second set
# print "n:",n,"a:",a,"b:",b,"c:",c,"d:",d
t = b - a + 1 # all posible variants of the first set
k = d - c + 1 # all posible variants of the second set
number_of_vars = 0
if t >= k:
while b >= a:
if (n - b <= d) \
and (n - b>= c):
number_of_vars += 1
b -= 1
else:
b -= 1
if t < k:
while d >= c:
if (n-d <= b) and (n-d >= a):
number_of_vars += 1
d -= 1
else:
d -= 1
print number_of_vars
No algorithm required -- just algebra:
It suffices to count the number of x in [a,b] for which z - x is in [c,d]
You need both a <= x <= b and c <= z - x <= d. The second inequality is equivalent to z - d <= x <= z - c hence you need
max(a, z - d) <= x <= min(b,z - c)
The number of such x is 0 if min(b,z - c) < max(a, z - d) otherwise it is
min(b,z - c) - max(a, z - d) + 1
In either case the number of solutions is
max(0, min(b,z - c) - max(a, z - d) + 1)
In your example a = c = 1 and b = d = z = 5 and
min(b, z - c) - max(a, z - d) + 1 = min(5,4) - max(1,0) + 1 = 4 - 1 + 1 = 4
One thing that you can use to reduce the checks in your algorithm is,
If the range for the 2 sets are overlapping, then you can cancel out some checks. Like in your example,
range for 1st set is 1 to 5
range for 2nd set is 1 to 5
So, if
x = 4, y = 1
is working, then
x = 1, y = 4
will also work. So you have to go only till half the number (i.e till 3 only in this case)
If only a part of the range is overlapping, then you can use the above method for that part, and the remaining part can be checked using normal method.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
Given a problem:
You have a certain amount of soldiers.
Each soldier has a given rank (some are officers, sergeants, etc). Now they are to go and kill some guys.
You have a limited amount of ammunition. Depending on the rank, each person is given a box of ammunition. The soldiers are standing in a straight line.
The person with a higher rank has to be given more ammunition if a person of lower rank is next to him.
Each person has to be given at least one box.
Example: using numbers from 1 upwards to represent rank: 4 2 3 2 2 1 3 6. the equivalent boxes of ammunition are: 2 1 2 1 2 1 2 3.
The fastest way for me to come up with the list of ammunition is to take the first three ranks and compare them to each other (i.e. from the example, I pick 4 2 3 ).Next I increment by one (i.e. 2 3 2) and make a comparison again. Obviously, this takes a lot of time.Is there a faster way?
NOTE: Soldiers with same rank standing next to each other don't care how much ammunition each has.
soldier_num = int(input())
i = 0
rating_array = []
ammo_array = []
can_can = soldier_num
while(i < soldier_num):
rating_array.append(int(input()))
ammo_array.append(1)
i += 1
i = 0
while(i < soldier_num):
if(i == 0):
if((rating_array[i] > rating_array[i+1]) and (ammo_array[i] <= ammo_array[i+1])):
ammo_array[i] += 1
i = i-1
can_can += 1
if(0<i<(soldier_num-1)):
if((rating_array[i] > rating_array[i+1]) and (ammo_array[i] <= ammo_array[i+1])):
ammo_array[i] += 1
i = i-1
can_can += 1
elif((rating_array[i] > rating_array[i-1]) and (ammo_array[i] <= ammo_array[i-1])):
ammo_array[i] += 1
i = i-1
can_can += 1
elif((rating_array[i] < rating_array[i-1]) and (ammo_array[i] >= ammo_array[i-1])):
ammo_array[i-1] += 1
i = i-1
can_can += 1
elif((rating_array[i] < rating_array[i+1]) and (ammo_array[i] >= ammo_array[i-1])):
ammo_array[i+1] += 1
i = i-1
can_can += 1
i += 1
if(i == (soldier_num-1)):
if((rating_array[i] > rating_array[i-1]) and (ammo_array[i] <= ammo_array[i-1])):
ammo_array[i] += 1
can_can += 1
print(can_can)
There are 4 possible categories for each number:
Both neighbors are higher (valley)
Both neighbors are lower (peak)
Left is higher, right is lower (downhill)
Right is higher, left is lower (uphill)
Count out-of-bounds indices as infinity when you're looking for valleys and 0 when looking for peaks. Since you say "neighbors of the same rank don't care", you can count them the same way.
First reduce all the valleys to 1. This should be straightforward.
To reduce the uphill elements, iterate through the array and reduce them to left+1.
To reduce the downhill ones, iterate backwards and reduce them to right+1.
Finally, peaks are lowered to whichever neighbor is higher, plus one.
For your example:
4 2 3 2 2 1 3 6 < original
4 1 3 1 2 1 3 6 < valleys reduced
4 1 3 1 2 1 2 3 < uphill reduced
2 1 3 1 2 1 2 3 < downhill reduced
2 1 2 1 2 1 2 3 < peaks reduced
Hint:You have to define peaks and valleys in this case. Peaks are elements that are >= their nieghbours. Valleys are elements <= their neighbours.
Assign 1 box to the valleys.
The peaks and valleys shall alternate. The number of boxes to peak = larger of distance from previous valley and next valley.