I want to find a number[i] of infinite sequence but it takes a long time in the following input.
Let's consider an infinite sequence of digits constructed of ascending powers of 10 written one after another. Here is the beginning of the sequence: 110100100010000... You are to find out what digit is located at the definite position of the sequence.
Input
There is the only integer N in the first line (1 ≤ N ≤ 65535). The i-th of N left lines contains the integer K[i] — the number of position in the sequence (1 ≤ K[i] ≤ 231 − 1).
Output
You are to output N digits 0 or 1 separated with a space. More precisely, the i-th digit of output is to be equal to the Ki-th digit of described above sequence.
INPUT
4
3
14
7
6
OUTPUT
0 0 1 0
Here's my code
x = input()
a = []
for i in range(x):
y = input()
a.append(y)
b = '1'
c = 1
for i in range(100):
c *= 10
b += str(c)
for i in range(x):
print b[a[i]-1],
You need to go beyond the basic description of the problem. If you generate the whole string, that'll be 2^31 characters long (and you'll need to go up to 65536, not 100). Fortunately, there is a better way. You don't really need the string. You just need a method to check if the character at a given index K[i] is 1.
The positions of all "1"s in the string correspond to the triangular numbers. The nth triangular number can be calculated via
x = n * (n + 1) / 2
By solving for n, we get
n = sqrt(2 * x + 0.25) - 0.5
If x is a triangular number, then n will be an integer, and the string will have a "1" on that position. Otherwise, a "0". Also, we have to use K[i] - 1, because the index in the problem is 1-based.
import math
import sys
f = lambda x: math.sqrt(2.0 * x + 0.25) - 0.5
g = lambda x: f(x) % 1 == 0
inp = map(int, sys.stdin.read().split()[1:])
print(" ".join("1" if g(x-1) else "0" for x in inp))
You should not generate a whole string here, rather than that use some maths. Here the numbers will be:
1
10
100
1000
10000
...
If you look at the series you'll notice that the 1's are at the position 1, 2, 4, 7, 11, ....
We can generalize this series using this formula (n^2 - n + 2)/2. So, the quadratic equation will become:
(n^2 - n + 2)/2 = i
#or n^2 - n + 2 - 2i
Where i is the current index coming from input.
Now, if for any i the output of b^2 - 4ac is a perfect square then it means the number is surely 1 otherwise it's 0.(Here value of a is 1, and b is -1 and we can calculate c using 2 - 2*i)
from math import sqrt
def solve(i):
b = -1
a = 1
c = 2 - 2 * i
val = (b**2) - (4*a*c)
sq = sqrt(val)
if int(sq) == sq:
return 1
return 0
for _ in xrange(input()):
print solve(input()),
Demo:
$ python so.py < foo.txt
0 0 1 0
It maybe take a lot of time because you are constructing the complete sequence of digits of ascending powers of 10. If you analyze the structure of the sequence you can notice some patter.
The patter in combination with the fact sum_{i=1}^n = (n+1)*n/2 gives the next solution, where the function digit_pow_10 can determinate directly if the digit in the position y is 1 or 0, without construction the complete sequence. If you need more details please contact me
import math
def digit_pow_10(y):
n = int(math.sqrt(0.25+2*y)-0.5)
diff = y - int(n*(n+1)/2.0)
if diff == 1 or y == 1:
return 1
else:
return 0
x = input()
for i in range(x):
y = input()
a.append(y)
for y in a:
print digit_pow_10(y),
Related
You are given an array A having N integers. An element X in A is called perfect if X can be written as Y**Z for any Y >0 and Z>1
1<= N <= 10^5
1<= A[i] <= 10^5
Input:
2
9
6
Output
1
9 can be written as 3^2
def solve(N,A):
count=0
for i in A:
for j in range(1,int(i)//2):
for k in range(1,int(j):
if j**k == int(i):
count=count+1
i = i + 1
return count
This approach gives me correct answer for any type of input in my system unless it is in competitive coding IDE
The error message read Time Limit Exceeded
How do I overcome this problem ?
You can try simple preprocessing.
First of all, based on limits you need to check approximately n * 20 numbers (because 2 ** 20 > N), so it's O(n) - good, next when you processed all possible numbers you can simply compare your input with preprocessed data as follows:
def solve(n, a):
MAXN = 10 ** 5 + 1
is_perfect = [False] * MAXN
for number in range(1, MAXN):
for power in range(2, 20):
if number ** power > MAXN:
break
is_perfect[number**power] = True
counter = 0
for element in a:
if is_perfect[element]:
counter = counter + 1
return counter
Final complexity is O(n)
I am doing an assessment that is asking by the given "n" as input which is a length of a stick; how many triangles can you make? (3 < n < 1,000,000)
For example:
input: N=8
output: 1
explanation:
(3,3,2)
input: N=12
output: 3
explanation:
(4,4,4) (4,5,3) (5,5,2)
Now the codes I wrote are returning 33 % accuracy as the web assessment is throwing time limit error.
ans = 0
n = int(input())
for a in range(1, n + 1):
for b in range(a, n - a + 1):
c = n - a - b
if a + b > c >= b:
ans += 1
print(ans)
code b:
ans = 0
n = int(input())
for i in range(1,n):
for j in range(i,n):
for c in range(j,n):
if(i+j+c==n and i+j>c):
ans+=1
print(ans)
How can this be made faster?
This is an intuitive O(n) algorithm I came up with:
def main():
n = int(input())
if n < 3:
print(0)
return
ans = n % 2
for a in range(2, n//2+1):
diff = n - a
if diff // 2 < a:
break
if diff % 2 == 0:
b = diff // 2
else:
b = diff // 2 + 1
b = max(b - a // 2, a)
c = n - b - a
if abs(b - c) >= a:
b += 1
c -= 1
ans += abs(b-c)//2 + 1
print(ans)
main()
I find the upper bound and lower bound for b and c and count the values in that range.
I thought of a completely different way to do it:
We take the smallest side and call it a. It can never be more than n/3, otherwise a different side would be the smallest.
We try to figure out what is the next smallest side (b):
We see what's left after reducing our a.
We divide it by 2 in order to find the middle where we'll start advancing from
We'll see how far we can get before the difference between the lengths is a (or the difference from the middle is a/2) as that's the minimum b side length that is possible and satisfies a+b>c. Basically, the second smallest side is a/2 less than the middle.
The smallest side is the maximum between our calculation or a, in caseb==a. b can never be lower than a as it violates our first rule that a is the smallest.
We figure out the difference from the middle and the smallest side. That's how many possible solutions we have for the other 2 sides.
Add everything together for every a and that's our solution.
The floor, ceil and % are fixes for when a is odd, the middle is .5, or +1 in case b+c is even, cause b==c is then possible.
Code:
import math
n = int(input("Enter a number: "))
total = 0
# a is the shortest side
for a in range(1, (n//3)+1):
length_left = n-a
middle_number = length_left/2
# Shortest potential side b where the distance between b and c is smaller than a (c-b < a)
b = middle_number-(math.ceil(a/2)-1)-((length_left % 2)/2)
# We calculate how far it is from the middle
max_distance_from_middle = middle_number - max(b, a)
# Add another 1 if the length is even, in case b==c
adding = math.floor(max_distance_from_middle) + (1 if length_left % 2 == 0 else 0)
total += adding
print(total)
Or in an ugly one-liner:
n = int(input("Enter a number: "))
print(sum(math.floor((n-a)/2 - max((n-a)/2 - math.ceil(a/2) + 1 - (((n-a) % 2)/2), a)) + 1 - ((n-a) % 2) for a in range(1, (n//3)+1)))
Alcuin's sequence expansion: O(1)
Alcuin's sequence [See: https://en.wikipedia.org/wiki/Alcuin%27s_sequence] is a series expansion of the polynomial below, where the nth coefficient corresponds to the nth answer, that is, the maximum amount of unique integer triangles with perimeter n.
The algorithmic implementation of this is simply a formula. The Online Encyclopaedia of Integer Sequences (OEIS) provides many formulas that achieve this, the simplest of which is:
round(n^2 / 48) (Even)
round((n+3)^2 / 48) (Odd)
[See: https://oeis.org/A005044]
This evidently has a constant time complexity, given that the only functions required are modulo 2, integer squared and round, each of which are constant time (under certain definitions).
Implementation
Expanded:
def triangles(n):
if n % 2 == 0:
return round(n ** 2 / 48)
else:
return round((n + 3) ** 2 / 48)
1-Liner:
def triangles(n): return round(n ** 2 / 48) if n%2==0 else round((n + 3) ** 2 / 48)
Or even:
def triangles(n): return round((n + 3 * n%2) ** 2 / 48)
Extra
No imports are needed.
As the OP questioned, why do we divide by 48? While I can't answer that explicitly, let's get an intuitive understanding. We are squaring numbers, so it is evidently going to expand greatly. By the time we get to 5, that would give 64 (8^2). So, there must be a constant (albeit a reciprocal) to restrict the growth of the parabola, thus the / 48.
When we graph the OP's method, it gives an alternating parabola. This explains why there is a back-and-forth with the +3 and +0.
https://mathworld.wolfram.com/AlcuinsSequence.html
import math
n = int(input())
print(round(n ** 2 / 48)) if n % 2 == 0 else print(round((n + 3)** 2 / 48))
How do i make three random negative numbers and three positive random numbers equal 1 constrained between -1 and 1. For example,
random_nums = np.array([-.2,-.3,-.5,.5,.8,.7])) = 1
I dont want np.uniform answers I need 6 random numbers in arr[0],arr[1],arr[2],arr[3],arr[4],arr[5],arr[6] =1. Then want to shuffle them in different order shuffle(random_nums).
Obviously, numbers generated by this scheme will never be truly "random", since to satisfy this constraint, you will have to, well, constrain some of them.
But, that warning aside, here's one way to generate such arrays:
Generate a pair (a,b) where a = rand(), and b=-rand()
If a+b < 0, reverse keep (a,b), otherwise a,b = -a, -b
Repeat with another pair (c,d)
If a+b+c+d < 1 then keep (c,d), otherwise c,d = -c, -d.
If a+b+c+d < 0 then a,b,c,d = -a, -b, -c, -d
You should now have a positive a+b+c+d. Obtain a random number e in the range [-(a+b+c+d), 0]
Your final number is f = 1 - (a+b+c+d+e)
rough (untested) example of python implementation:
def getSix():
a = numpy.random.rand()
b = -numpy.random.rand()
a,b = (a,b) if a+b > 0 else (-a,-b)
c = numpy.random.rand()
d = -numpy.random.rand()
c,d = (c,d) if a+b+c+d < 1 else (-c, -d)
a,b,c,d = (a,b,c,d) if a+b+c+d > 0 else (-a, -b, -c, -d)
e = -numpy.random.rand()*(a+b+c+d)
f = 1 - (a+b+c+d+e)
return numpy.array([a,b,c,d,e,f])
Obviously this is very specific to your case of 6 elements, but you could figure out a way to generalise it to more elements if necessary.
It's may be counter-intuitive, but actually, you can't :
1) the last one of them must be non-random so that the sum equals 1.
2) the penultimate must be in an interval such that when summed with
the first four, the result is between 0 and 2.
3) the antepenultimate must be in an interval such that when summed with
the first three, the result is between -1 and 3. and so on...
The numbers are constrained, so they can't be random.
What you can do to approach the solution is to use a backtracking algorithm.
There is no solution to your problem. Your problem can be formulated with the following equation:
x + y + z + p + q + r = 1, where x, y, z > 0 and p, q, r < 0.
As you can see, this is an indeterminate equation. This means that it has infinite solutions, thus your requirements cannot be met.
Not truly random due to the sum constraint and a floating point sum to an exact value can be problematic due to floating point rounding as well, but with a little brute force, the Decimal module and computing the sixth value of five random numbers, the following example works.
The code below generates five random numbers and computes sixth for the sum requirement and loops until 3 of 6 numbers are negative:
from decimal import Decimal
import random
def get_nums():
while True:
# Use integers representing 100ths to prevent float rounding error.
nums = [random.randint(-100,100) for _ in range(5)]
nums.append(100-sum(nums)) # compute 6th number so sum is 100.
# Check that 6th num is in right range and three are negative.
if -100 <= nums[5] <= 100 and sum([1 if num < 0 else 0 for num in nums]) == 3:
break
return [Decimal(n) / 100 for n in nums]
for _ in range(10):
print(get_nums())
Output:
[Decimal('-0.36'), Decimal('0.89'), Decimal('0.39'), Decimal('1'), Decimal('-0.05'), Decimal('-0.87')]
[Decimal('-0.01'), Decimal('0.12'), Decimal('0.98'), Decimal('-0.48'), Decimal('-0.45'), Decimal('0.84')]
[Decimal('0.99'), Decimal('0.5'), Decimal('-0.29'), Decimal('0.49'), Decimal('-0.65'), Decimal('-0.04')]
[Decimal('0.51'), Decimal('-0.03'), Decimal('0.64'), Decimal('-0.96'), Decimal('0.99'), Decimal('-0.15')]
[Decimal('0.51'), Decimal('-0.27'), Decimal('-0.62'), Decimal('0.67'), Decimal('-0.22'), Decimal('0.93')]
[Decimal('-0.25'), Decimal('0.84'), Decimal('-0.23'), Decimal('-0.59'), Decimal('0.94'), Decimal('0.29')]
[Decimal('0.75'), Decimal('-0.39'), Decimal('0.86'), Decimal('-0.81'), Decimal('0.6'), Decimal('-0.01')]
[Decimal('-0.4'), Decimal('-0.46'), Decimal('0.89'), Decimal('0.94'), Decimal('0.27'), Decimal('-0.24')]
[Decimal('-0.87'), Decimal('0.6'), Decimal('0.95'), Decimal('-0.12'), Decimal('0.9'), Decimal('-0.46')]
[Decimal('0.5'), Decimal('-0.58'), Decimal('-0.04'), Decimal('-0.41'), Decimal('0.68'), Decimal('0.85')]
Here is a simple approach that uses sum-normalization:
import numpy as np
def gen_rand(n):
result = np.array((np.random.random(n // 2) + 1).tolist() + (np.random.random(n - n // 2) - 1).tolist())
result /= np.sum(result)
return result
rand_arr = gen_rand(6)
print(rand_arr, np.sum(rand_arr))
# [ 0.70946589 0.62584558 0.77423647 -0.51977241 -0.28432949 -0.30544603] 1.0
Basically, we generate N / 2 numbers in the range (1, 2) and N / 2 numbers in the range (0, -1) and then these gets sum-normalized.
The algorithm does not guarantee exact results, but as N increases the probability of invalid results goes to zero.
N = 100000
failures = 0
for i in range(N):
rand_arr = gen_rand(6)
if np.any(rand_arr > 1) or np.any(rand_arr < -1):
failures += 1
print(f'Drawings: {N}, Failures: {failures}, Rate: {failures / N:.2%}')
# Drawings: 100000, Failures: 1931, Rate: 1.93%
Therefore, you could just combine it with some other logic to just discard invalid generations, if you are strict on the requirements, e.g.:
import numpy as np
def gen_rand_strict(n):
result = np.full(n, 2.0, dtype=float)
while np.any(result > 1) or np.any(result < -1):
result = np.array((np.random.random(n // 2) + 1).tolist() + (np.random.random(n - n // 2) - 1).tolist())
result /= np.sum(result)
return result
rand_arr = gen_rand_strict(6)
print(rand_arr, np.sum(rand_arr))
# [ 0.55928446 0.5434739 0.38103321 -0.24799626 -0.09556285 -0.14023246] 1.0
N = 100000
failures = 0
for i in range(N):
rand_arr = gen_rand_strict(6)
if np.any(rand_arr > 1) or np.any(rand_arr < -1):
failures += 1
print(f'Drawings: {N}, Failures: {failures}, Rate: {failures / N:.2%}')
# Drawings: 100000, Failures: 0, Rate: 0.00%
Actually, with the logic to ensure values within the exact range, you do not need to put much thinking into the ranges and this would also work well:
import numpy as np
def gen_rand_strict(n):
result = np.full(n, 2.0, dtype=float)
while np.any(result > 1) or np.any(result < -1):
result = np.array((np.random.random(n // 2) * n).tolist() + (np.random.random(n - n // 2) * -n).tolist())
result /= np.sum(result)
return result
rand_arr = gen_rand_strict(6)
print(rand_arr, np.sum(rand_arr))
# [ 0.32784034 0.75649476 0.8097567 -0.2923395 -0.41629451 -0.1854578 ] 1.0
N = 100000
failures = 0
for i in range(N):
rand_arr = gen_rand_strict(6)
if np.any(rand_arr > 1) or np.any(rand_arr < -1):
failures += 1
print(f'Drawings: {N}, Failures: {failures}, Rate: {failures / N:.2%}')
# Drawings: 100000, Failures: 0, Rate: 0.00%
Examples,
1.Input=4
Output=111
Explanation,
1 = 1³(divisors of 1)
2 = 1³ + 2³(divisors of 2)
3 = 1³ + 3³(divisors of 3)
4 = 1³ + 2³ + 4³(divisors of 4)
------------------------
sum = 111(output)
1.Input=5
Output=237
Explanation,
1 = 1³(divisors of 1)
2 = 1³ + 2³(divisors of 2)
3 = 1³ + 3³(divisors of 3)
4 = 1³ + 2³ + 4³(divisors of 4)
5 = 1³ + 5³(divisors of 5)
-----------------------------
sum = 237 (output)
x=int(raw_input().strip())
tot=0
for i in range(1,x+1):
for j in range(1,i+1):
if(i%j==0):
tot+=j**3
print tot
Using this code I can find the answer for small number less than one million.
But I want to find the answer for very large numbers. Is there any algorithm
for how to solve it easily for large numbers?
Offhand I don't see a slick way to make this truly efficient, but it's easy to make it a whole lot faster. If you view your examples as matrices, you're summing them a row at a time. This requires, for each i, finding all the divisors of i and summing their cubes. In all, this requires a number of operations proportional to x**2.
You can easily cut that to a number of operations proportional to x, by summing the matrix by columns instead. Given an integer j, how many integers in 1..x are divisible by j? That's easy: there are x//j multiples of j in the range, so divisor j contributes j**3 * (x // j) to the grand total.
def better(x):
return sum(j**3 * (x // j) for j in range(1, x+1))
That runs much faster, but still takes time proportional to x.
There are lower-level tricks you can play to speed that in turn by constant factors, but they still take O(x) time overall. For example, note that x // j == 1 for all j such that x // 2 < j <= x. So about half the terms in the sum can be skipped, replaced by closed-form expressions for a sum of consecutive cubes:
def sum3(x):
"""Return sum(i**3 for i in range(1, x+1))"""
return (x * (x+1) // 2)**2
def better2(x):
result = sum(j**3 * (x // j) for j in range(1, x//2 + 1))
result += sum3(x) - sum3(x//2)
return result
better2() is about twice as fast as better(), but to get faster than O(x) would require deeper insight.
Quicker
Thinking about this in spare moments, I still don't have a truly clever idea. But the last idea I gave can be carried to a logical conclusion: don't just group together divisors with only one multiple in range, but also those with two multiples in range, and three, and four, and ... That leads to better3() below, which does a number of operations roughly proportional to the square root of x:
def better3(x):
result = 0
for i in range(1, x+1):
q1 = x // i
# value i has q1 multiples in range
result += i**3 * q1
# which values have i multiples?
q2 = x // (i+1) + 1
assert x // q1 == i == x // q2
if i < q2:
result += i * (sum3(q1) - sum3(q2 - 1))
if i+1 >= q2: # this becomes true when i reaches roughly sqrt(x)
break
return result
Of course O(sqrt(x)) is an enormous improvement over the original O(x**2), but for very large arguments it's still impractical. For example better3(10**6) appears to complete instantly, but better3(10**12) takes a few seconds, and better3(10**16) is time for a coffee break ;-)
Note: I'm using Python 3. If you're using Python 2, use xrange() instead of range().
One more
better4() has the same O(sqrt(x)) time behavior as better3(), but does the summations in a different order that allows for simpler code and fewer calls to sum3(). For "large" arguments, it's about 50% faster than better3() on my box.
def better4(x):
result = 0
for i in range(1, x+1):
d = x // i
if d >= i:
# d is the largest divisor that appears `i` times, and
# all divisors less than `d` also appear at least that
# often. Account for one occurence of each.
result += sum3(d)
else:
i -= 1
lastd = x // i
# We already accounted for i occurrences of all divisors
# < lastd, and all occurrences of divisors >= lastd.
# Account for the rest.
result += sum(j**3 * (x // j - i)
for j in range(1, lastd))
break
return result
It may be possible to do better by extending the algorithm in "A Successive Approximation Algorithm for Computing the Divisor Summatory Function". That takes O(cube_root(x)) time for the possibly simpler problem of summing the number of divisors. But it's much more involved, and I don't care enough about this problem to pursue it myself ;-)
Subtlety
There's a subtlety in the math that's easy to miss, so I'll spell it out, but only as it pertains to better4().
After d = x // i, the comment claims that d is the largest divisor that appears i times. But is that true? The actual number of times d appears is x // d, which we did not compute. How do we know that x // d in fact equals i?
That's the purpose of the if d >= i: guarding that comment. After d = x // i we know that
x == d*i + r
for some integer r satisfying 0 <= r < i. That's essentially what floor division means. But since d >= i is also known (that's what the if test ensures), it must also be the case that 0 <= r < d. And that's how we know x // d is i.
This can break down when d >= i is not true, which is why a different method needs to be used then. For example, if x == 500 and i == 51, d (x // i) is 9, but it's certainly not the case that 9 is the largest divisor that appears 51 times. In fact, 9 appears 500 // 9 == 55 times. While for positive real numbers
d == x/i
if and only if
i == x/d
that's not always so for floor division. But, as above, the first does imply the second if we also know that d >= i.
Just for Fun
better5() rewrites better4() for about another 10% speed gain. The real pedagogical point is to show that it's easy to compute all the loop limits in advance. Part of the point of the odd code structure above is that it magically returns 0 for a 0 input without needing to test for that. better5() gives up on that:
def isqrt(n):
"Return floor(sqrt(n)) for int n > 0."
g = 1 << ((n.bit_length() + 1) >> 1)
d = n // g
while d < g:
g = (d + g) >> 1
d = n // g
return g
def better5(x):
assert x > 0
u = isqrt(x)
v = x // u
return (sum(map(sum3, (x // d for d in range(1, u+1)))) +
sum(x // i * i**3 for i in range(1, v)) -
u * sum3(v-1))
def sum_divisors(n):
sum = 0
i = 0
for i in range (1, n) :
if n % i == 0 and n != 0 :
sum = sum + i
# Return the sum of all divisors of n, not including n
return sum
print(sum_divisors(0))
# 0
print(sum_divisors(3)) # Should sum of 1
# 1
print(sum_divisors(36)) # Should sum of 1+2+3+4+6+9+12+18
# 55
print(sum_divisors(102)) # Should be sum of 2+3+6+17+34+51
# 114
This question already has an answer here:
Random walk's weird outcome in python 3?
(1 answer)
Closed 6 years ago.
I am having unexpected outputs with the following code:
import random
N = 30 # number of steps
n = random.random() # generate a random number
x = 0
y = 0
z = 0
count = 0
while count <= N:
if n < 1/3:
x = x + 1 # move east
n = random.random() # generate a new random number
if n >= 1/3 and n < 2/3:
y = y + 1 # move north
n = random.random() # generate a new random number
if n >= 2/3:
z = z + 1 # move up
n = random.random() # generate a new random number
print("(%d,%d,%d)" % (x,y,z))
count = count + 1
When I run the code, the problem is:
Code output displays 31 coordinates, 1 more than the number of steps (N) variable.
Each iteration for 1 step should take only 1 step but it sometimes take multiple steps.
When I tested the code, the problem is ensured. To test the code, I assigned N = 1, and saw the following output:
(-1,0,1) This should be the initial step, but it took multiple steps (both x-1 and z+1), how could this happen?
(-2,0,1) Number of step variable (N) = 1 but this is the second output, why was it displayed?
Thanks for helping
N is 30, so count goes from 0 to 30. Since 30 <= 30 you will run the loop for count=0, 1, ..., 29 AND 30 which is 31 times
When you take a step, you don't ensure that another step is NOT taken. If random happens, you could enter the second or third if after already being in a previous one in the same loop iteration
You are dividing two ints which will only result in another int. So basically your code is do the following:
if n < 0:
x = x + 1 # move east
n = random.random() # generate a new random number
if n >= 0 and n < 1:
y = y + 1 # move north
n = random.random() # generate a new random number
if n >= 1:
z = z + 1 # move up
n = random.random()
fix by changing each if line to include a floating point number
if n < 1.0/3