{"id":60,"date":"2008-07-30T20:21:47","date_gmt":"2008-07-31T04:21:47","guid":{"rendered":"http:\/\/blog.richardkiss.com\/?p=60"},"modified":"2021-02-06T20:25:31","modified_gmt":"2021-02-07T04:25:31","slug":"google-code-peanut-butter-and-jam","status":"publish","type":"post","link":"https:\/\/blog.richardkiss.com\/?p=60","title":{"rendered":"Google Code (Peanut Butter and) Jam"},"content":{"rendered":"<p>Last Friday, I participated in the Google Code Jam, a programming puzzle contest sponsored by Google. It was the first qualification round, and I was very happy with how I did, coming in 74th in my heat (there were three heats, and mine had almost 3000 participants).<\/p>\n<p>There were three problems, each with two data sets. The last problem was really more of a math problem, which I figured would have given me more of an edge because most of the time when I cheat on my second love, computers, it&#8217;s with my first love, math. However, I couldn&#8217;t complete it in the time allotted. But I also couldn&#8217;t stop thinking about it. I eventually came up with a solution which I&#8217;ll share here.<\/p>\n<p>It&#8217;s problem C in round 1A (start <a href=\"http:\/\/code.google.com\/codejam\/contest\/\">here<\/a>), but essentially, you have to find the last three digits before the decimal point for the number (3 + ?5)<sup>n<\/sup> where n is a whole number that can be very large (up to two billion).<\/p>\n<p>This means you cannot calculate the whole thing; it would contain several hundred million digits, which would use most of RAM just to hold the representation. So you have to figure out a trick.<\/p>\n<p>Here&#8217;s what I came up with (too late to submit). Let A<sub>n<\/sub> =  (3 + ?5)<sup>n<\/sup> and B<sub>n<\/sub> =  (3 &#8211; ?5)<sup>n<\/sup>. Observe that A<sub>n<\/sub> = X<sub>n<\/sub> + Y<sub>n<\/sub>?5 for some series X<sub>0<\/sub>, X<sub>1<\/sub>, &#8230; and Y<sub>0<\/sub>, Y<sub>1<\/sub>, &#8230; where each of X<sub>n<\/sub> and Y<sub>n<\/sub> are whole numbers. You can show this easily by induction. You can show a similar thing for B<sub>n<\/sub>; in fact, B<sub>n<\/sub> = X<sub>n<\/sub> &#8211; Y<sub>n<\/sub>?5.<\/p>\n<p>This means that A<sub>n<\/sub>+B<sub>n<\/sub> = 2X<sub>n<\/sub>.<\/p>\n<p>Notice that  (3 &#8211; ?5) &lt; 1, so B<sub>n<\/sub> &lt; 1 for n&gt;1, and goes towards 0 very quickly. Since A<sub>n<\/sub> = 2X<sub>n<\/sub> &#8211; B<sub>n<\/sub>, we can calculate A<sub>n<\/sub> by calculating 2X<sub>n<\/sub> and subtracting a &#8220;small&#8221; number&#8230; that is, the last three digits of A<sub>n<\/sub> are the same as the last three digits of 2X<sub>n<\/sub>-1.<\/p>\n<p>So all we need to do is figure out X<sub>n<\/sub>!<\/p>\n<p>We know that X<sub>0<\/sub> = 1, Y<sub>0<\/sub> = 0. A<sub>n+1<\/sub> = A<sub>n<\/sub>(3 + ?5), so<\/p>\n<p>X<sub>n+1<\/sub> + Y<sub>n+1<\/sub>?5 = A<sub>n+1<\/sub> = A<sub>n<\/sub>(3 + ?5) = (X<sub>n<\/sub> + Y<sub>n<\/sub>?5)(3 + ?5) = (3X<sub>n<\/sub>+5Y<sub>n<\/sub>)+?5(X<sub>n<\/sub>+3Y<sub>n<\/sub>)<\/p>\n<p>so separating rational and irrational parts yields the pretty recurrence relation X<sub>n+1<\/sub> = 3X<sub>n<\/sub> + 5Y<sub>n<\/sub> and Y<sub>n+1<\/sub> = X<sub>n<\/sub>+3Y<sub>n<\/sub>.<\/p>\n<p>That means X<sub>n+1<\/sub> and Y<sub>n+1<\/sub> depend only upon X<sub>n<\/sub> and Y<sub>n<\/sub>. Since we only care about the last three digits, that means that there are only 1000*1000=a million different combinations of X<sub>n<\/sub>, Y<sub>n<\/sub>, and thus, the series must repeat in fewer than a million iterations. It shouldn&#8217;t be too hard to find a repeat.<\/p>\n<p>Here&#8217;s the Python code to find the cycle length:<\/p>\n<pre>\r\ndef _a_b_n(n):\r\n    if n == 0:\r\n        return 3,1\r\n    a,b = a_b_n(n-1)\r\n    return ((3*a+5*b) % 1000, (a+3*b) % 1000)\r\n\r\nCACHE={}\r\ndef a_b_n(n):\r\n    if not CACHE.has_key(n):\r\n    CACHE[n] = _a_b_n(n)\r\n    return CACHE[n]\r\n\r\nF={}\r\nfor i in xrange(int(1e6)):\r\n    k = (Xn, Yn) = a_b_n(i)\r\n    #print i, a, b, (2*a-1)%1000\r\n    if F.has_key(k):\r\n    #print \"repeat: %d, %d\" % (i,F[k])\r\n    break\r\n    F[k] = i\r\n\r\ncycle_length = i-F[k]\r\nprint \"cycle length is\", cycle_length\r\n<\/pre>\n<p>When you run this, it takes less than a tenth of a second to figure out that the cycle length is 500, and A<sub>503<\/sub>, B<sub>503<\/sub> = A<sub>3<\/sub>, B<sub>3<\/sub>. So now it&#8217;s easy! Calculating the first 503 terms is enough.<\/p>\n<p>Here is the rest of the code:<\/p>\n<pre>\r\ndef do_trial(f):\r\n    n = int(f.readline())\r\n    if n&gt;cycle_length:\r\n        n %= cycle_length\r\n        n += cycle_length\r\n    t = a_b_n(n-1)\r\n    return (2*t[0]-1) % 1000\r\n\r\nf = sys.stdin\r\ncount = int(f.readline())\r\nfor i in xrange(count):\r\nv = do_trial(f)\r\nprint \"Case #%d: %03d\" % (i+1, v)\r\n<\/pre>\n<p>It runs in pretty much no time at all, thanks to the excessive caching.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last Friday, I participated in the Google Code Jam, a programming puzzle contest sponsored by Google. It was the first qualification round, and I was very happy with how I did, coming in 74th in my heat (there were three heats, and mine had almost 3000 participants). There were three problems, each with two data &hellip; <a href=\"https:\/\/blog.richardkiss.com\/?p=60\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Google Code (Peanut Butter and) Jam<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,5],"tags":[9,10,11],"class_list":["post-60","post","type-post","status-publish","format-standard","hentry","category-computers","category-life","tag-google-code-jam","tag-programming","tag-python"],"_links":{"self":[{"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=\/wp\/v2\/posts\/60","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=60"}],"version-history":[{"count":1,"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=\/wp\/v2\/posts\/60\/revisions"}],"predecessor-version":[{"id":658,"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=\/wp\/v2\/posts\/60\/revisions\/658"}],"wp:attachment":[{"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=60"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=60"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.richardkiss.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=60"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}