Even without deducing a general algorithm, here's how I would have written it, in Python as well:
def largest_decent_number_of_length(N):
for num_threes in xrange(0, N, 5):
num_fives = length - num_threes
if num_fives % 3 == 0:
return "5" * num_fives + "3" * num_threes
else:
return "-1"
if __name__ == "__main__":
T = raw_input('')
for _ in range(0, T):
N = raw_input('')
print largest_decent_number_of_length(N)
This solution to me is more clear because it doesn't do magic with modulo to determine the case we are in, and incorporates some points which I feel are important for clear code.
First of all, as jonrsharpe also mentioned: if you want to do code executing at the top level, do it in an if __name__ == "__main__": section. This will only execute when directly run, but not when imported. However, this is something python specific, and in another language you would have to do this in a different fashion.
Second: The variable names are quite specific, num_threes and num_fives are more clear than i and j. I could have gone overboard, and have written number_of_threes but that would have made the names overly long, and thus less readable for such a short piece of code. The T and N however are quite short, but they are a direct translation from the document. I could have named them num_challenges and challenge, but that isn't necessary---assuming the reader also read the challenge itself. Another thing I always try to do is make function names read like descriptions, especially when the variables are filled in. This doesn't work often, but in the cases where you can, I believe it makes code more readable. "print largest decent number of length N" sounds like a clear task to me.
Third: After reading this, you should be able to follow my logic---I hope. The largest number will start with 5s, followed by 3s --- interchanging a 5 and a 3 would make the number smaller. Also, less 3s means more 5s, so we start with as few 3s as possible, and add as few as possible while still satisfying the second requirement (num_threes % 5 == 0). For each of these options, we check if the number of fives also satisfies the requirements, and if so, we print the number.
Fourth: we don't print the number, but return it, making the function reusable. (Not that important in this case, but I would just like to mention it). The main loop is concerned with reading numbers, and printing results. The function is concerned with finding the answer. The responsibilities are separated.
Fifth: The value returned is in both cases of the same type (a string, twice). Returning a string instead of a number is an arbitrary choice, however one that followed quite easily from the manipulations involved. One could decide to make it an integer instead, by writing return int("5" * num_fives + "3" * num_threes) and return -1. Both are a viable solution, and if I had to extend on this I would probably choose to go for wrapping the int(...) around it. However, the most important thing is that the function returns items of only one type.
Sixth: One of the nice things of python is the for...else construct. The else portion is executed when break/return is not called from within the loop. Using this, you don't have to use a variable flag that gets set on each point where you break from the loop. I admit it is a weird feature and it took me quite some time to get used to it, but it is ideally suited for the loops where you try to find an item satisfying a condition. If you found it, you can just break. If you haven't found it, the else will be executed instead.