I am working on the USACO problem Arithmetic Progression
. Here is their problem statement:
An arithmetic progression is a sequence of the form a, a+b, a+2b, ..., a+nb where n=0, 1, 2, 3, ... . For this problem, a is a non-negative integer and b is a positive integer.
Write a program that finds all arithmetic progressions of length n in the set S of bisquares. The set of bisquares is defined as the set of all integers of the form p² + q² (where p and q are non-negative integers).
Furthermore, input is read from a file ariprog.in
, and output should be written to another file ariprog.out
. Help is not required for this part, but a sample ariprog.in
is shown below:
5 7
And here is the input format:
Line 1: N (3≤N≤25), the length of progressions for which to search
Line 2: M (1≤M≤250), an upper bound to limit the search to the bisquares with 0≤p,q≤M.
And here is the output format:
If no sequence is found, a single line reading `NONE'. Otherwise, output one or more lines, each with two integers: the first element in a found sequence and the difference between consecutive elements in the same sequence. The lines should be ordered with smallest-difference sequences first and smallest starting number within those sequences first.
There will be no more than 10,000 sequences.
For my code, here are my steps.
- Read the file and save variables
N
andM
- Generate all possible bi-squares (p² + q²) and save it to a list
- Loop through starting values for arithmetic progressions
- Loop through ending values for arithmetic progressions
- If the end of a possible sequence (calculated with
start + (length - 1) * difference
is larger than the largest value in the list of possible bi-squares (found in step 2), skip this case - Test a starting value and difference by looping through it until the length is achieved
- Sort the list according to output format
- Write to file
Out of these, steps 3-6 take the time. I am interested in speed improvements and optimizations, not a full solution.
My logic is working, I pass 5/9 of the tests. I fail on the test case with the input being 18 100 due to too much time taken
Now, here is the actual code so far:
'''
ID: ***
LANG: PYTHON3
TASK: ariprog
'''
#import os
#try:
# os.chdir(os.path.dirname(__file__))
#except:
# pass
#import time
from itertools import combinations_with_replacement
with open('ariprog.in', 'r') as file:
N, M = map(int, [line.replace('\n', '') for line in file.readlines()])
def calculateBisquares(limit):
p_or_q_values = range(limit+1)
return sorted(list(set([((i[0]**2) + (i[1]**2)) for i in combinations_with_replacement(p_or_q_values, 2)])))
def checkNum(bisquare_index, all_bisquares, difference):
for sequence_item_number in range(2, N):
if(int(all_bisquares[bisquare_index] + difference * sequence_item_number) not in all_bisquares):
return False
return True
#print(f'starting: {time.time()}')
#start = time.time()
all_bisquares = calculateBisquares(M)
maximum_number = 2 * (M ** 2)
sequences = []
for starting_index in range(0, len(all_bisquares) - N + 1):
for ending_index in range(starting_index + 1, len(all_bisquares) - N + 2):
difference = all_bisquares[ending_index] - all_bisquares[starting_index]
if all_bisquares[starting_index] + (N - 1) * difference > maximum_number:
break
if checkNum(starting_index, all_bisquares, difference):
sequences.append([all_bisquares[starting_index], difference])
if len(sequences) != 0:
sequences.sort(key=lambda d: d[1])
out = '\n'.join([' '.join(list(map(str, sequence))) for sequence in sequences])
else:
out = 'NONE'
#print(f'ending: {time.time()}')
#print(f'time taken: {time.time()-start}')
with open('ariprog.out', 'w') as file:
file.write(out + '\n')
Side note: I am interested in an optimization but haven't yet implemented in Python.