dp = [[0 for i in xrange(5005)] for i in xrange(5005)]
def f_f(c,t):
if (dp[c][t] != 0):
return dp[c][t] - 1;
if (t==1):
return 1;
ret = 0
i = int(c/t)
while(i >= 0):
ret=ret+ f_f (c-i*t, t-1)
if ret >= 1988:
ret %= 1988
i = i - 1
dp[c][t] = 1 + ret
return dp[c][t] - 1
while(1):
o = raw_input();
s = map(int,o.split())
a = s[0]
b = s[1]
if (a == 0 and b == 0):
break
print f_f(a-b,b)
Zlobober mentions in a comment here that wrapping your program in a function can speed it up.
Slowness aside, I ran this code on my computer with
5000 5000
as input and got a stack overflow (with both CPython and PyPy).Should do the trick.
first:
second: get rid of recursion
Yeah, I wanted to say the same about the recursion—and it has to be removed or improved to fix the stack overflow anyway—but when I actually tried to remove the recursion, the DP loop ran so slow that I didn’t have the patience to wait for it to finish under CPython. Even under PyPy, it took more than 70 seconds on my machine (a 2010 laptop with a then-high-end Core i7).
I don’t think your suggestion about the modulus operator helps at all though. In fact, I’d suggest doing exactly the opposite: just
ret %= 1998
without any conditions; but that doesn’t affect performance either.There’s plenty of small things that are too slow or just horrible in this piece of Python, but changing none of them gave any measurable impact on the performance in my tests.
The only thing that helped was wrapping all code in a function like the comment above said. That actually reduced the runtime by a third! And in both CPython and PyPy.
I think %= is slower than if and -=
Also can help single one %= after while loop.
Sometimes regardless of no matter how you speed it up it won't pass, especially on sites like SPOJ that are most anti anything but C++. Many times JAVA doesn't even pass on SPOJ ( like literally no single accepted solution), so let alone Python.
the complexity of your code is actually O(N * N * log(N)) but you can reduce it to O(N * N> By using prefix sums , the normal recurrence is dp[n][k] = sum(dp[n — i * k][k — 1]) , but you can use prefix sum here , you can create another dp like dp2[n][k] denotes sum of all dp[n][k] + dp[n — i * (k + 1)][k] and then dp[n][k] will just be equal to dp2[n][k] and dp2[n][k] can be updated like dp2[n][k] = dp2[n — k — 1][k] + dp[n][k] . Here is the code . Edit , you dont even need prefix sum , just change the recurance to dp[n][k] = dp[n][k — 1] + dp[n — k][k] and done. code