{"id":968,"date":"2020-04-12T11:52:10","date_gmt":"2020-04-12T18:52:10","guid":{"rendered":"http:\/\/209.126.2.187\/?p=968"},"modified":"2021-07-04T21:26:27","modified_gmt":"2021-07-05T04:26:27","slug":"binary-exponentiation-dp-counting","status":"publish","type":"post","link":"https:\/\/nanzhou.cc\/index.php\/2020\/04\/12\/binary-exponentiation-dp-counting\/","title":{"rendered":"Linear Recurrence Relation &#038; Binary Exponentiation &#038; DP Counting"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Summary <\/h2>\n\n\n\n<p>In this post, I will introduce a common technique in some DP counting problems: binary exponentiation. <\/p>\n\n\n\n<p>Typically, in these problems, you will be given a number <code>n<\/code> and you are asked to return the number of valid combinations. You need to figure out the initial state and the transform function between states. The problems then could be solved by DP. <\/p>\n\n\n\n<p>During the iteration, if the the current state and the previous states has a <strong>linear<\/strong> <strong>recurrence relation<\/strong>. Then a bonus is that you could use <strong>binary exponentiation<\/strong> of square matrixes to reduce the complexity to <code>log(n)<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">OJ<\/h2>\n\n\n\n\n<table id=\"tablepress-9\" class=\"tablepress tablepress-id-9\">\n<thead>\n<tr class=\"row-1\">\n\t<td class=\"column-1\"><\/td><th class=\"column-2\">Trick<\/th><th class=\"column-3\">Difficulty<\/th>\n<\/tr>\n<\/thead>\n<tbody class=\"row-striping row-hover\">\n<tr class=\"row-2\">\n\t<td class=\"column-1\"><a href=\"https:\/\/leetcode.com\/problems\/number-of-ways-to-paint-n-3-grid\/\" target=\"_blank\" rel=\"noopener noreferrer\"> 1411. Number of Ways to Paint N \u00d7 3 Grid <\/a><\/td><td class=\"column-2\">DP in Linear Structures + Binary Exponentiation<\/td><td class=\"column-3\">6 points<\/td>\n<\/tr>\n<tr class=\"row-3\">\n\t<td class=\"column-1\"><a href=\"https:\/\/leetcode.com\/problems\/knight-dialer\/\" target=\"_blank\" rel=\"noopener noreferrer\"> 935. Knight Dialer<\/a><\/td><td class=\"column-2\">DP in Linear Structures + Binary Exponentiation<\/td><td class=\"column-3\">5-6 points<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<!-- #tablepress-9 from cache -->\n\n\n\n<h2 class=\"wp-block-heading\">Details<\/h2>\n\n\n\n<h4 class=\"wp-block-heading\"><a rel=\"noreferrer noopener\" href=\"https:\/\/leetcode.com\/problems\/number-of-ways-to-paint-n-3-grid\/\" target=\"_blank\">LC 1411. Number of Ways to Paint N \u00d7 3 Grid<\/a><\/h4>\n\n\n\n<p>A naive <code>O(12*12*3 n)<\/code> solution is not difficult. The number of states is <code>12n<\/code>. At each <code>i<\/code>, it takes <code>O(12*3)<\/code> time to see if the current option has conflicts with the previous one. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">alg[i][prev] = sum {(alg[i + 1][curr]) if curr &amp; prev not conflict, for curr in 12 options}\n\/\/ alg[n - 1][prev] = sum {1 if ok(curr, prev) for curr in 12 options}<\/code><\/pre>\n\n\n\n<p>A better DP will decrease the number of states. At each <code>i<\/code>, the number of states now becomes 2, either in pattern 121, or pattern 123. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">pattern 121: 121, 131, 212, 232, 313, 323.\npattern 123: 123, 132, 213, 231, 312, 321.<\/code><\/pre>\n\n\n\n<p>We consider the next possible pattern for each current pattern.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">Patter 121 can be followed by: 212, 213, 232, 312, 313;\n3 121s, 2 123s \n\nPatter 123 can be followed by: 212, 231, 312, 232; \n2 121s, 2 123s<\/code><\/pre>\n\n\n\n<p>We can write the following transform equation.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">\/\/ alg[i][0]: 121, alg[i][1]: 123\nalg[i][0] = alg[i + 1][0] * 3 + alg[i + 1][1] * 2\nalg[i][1] = alg[i + 1][0] * 2 + alg[i + 1][1] * 2\n[alg[i][0],    [[3, 2]   [alg[i + 1][0],  \n alg[i][1]] =   [2, 2]]   alg[i + 1][1]]\n\/\/ [alg[n - 1][0],    [6,\n    alg[n - 1][1]] =   6]<\/code><\/pre>\n\n\n\n<p>Once we get the square matrix as the transform function, we could apply the binary exponentiation for matrixes to reduce the complexity. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"cpp\" class=\"language-cpp\">\/\/ The final result will be \n\/\/ fastPow(a, n - 1) * [6, 6]\nvector&lt;vector&lt;ll&gt;&gt; modMul(vector&lt;vector&lt;ll&gt;&gt; const &amp;a, vector&lt;vector&lt;ll&gt;&gt; const &amp;b) {\n    int n = a.size();\n    vector&lt;vector&lt;ll&gt;&gt; result(n, vector&lt;ll&gt;(n));\n    for (int i = 0; i &lt; n; ++i) {\n        for (int j = 0; j &lt; n; ++j) {\n            for (int k = 0; k &lt; n; ++k) {\n                result[i][j] += a[i][k] * b[k][j];\n                result[i][j] %= MOD;\n            }\n        }\n    }\n    return result;\n}\n\nvector&lt;vector&lt;ll&gt;&gt; fastPow(vector&lt;vector&lt;ll&gt;&gt; const &amp;a, int n) {\n    if (n == 0) {\n        int n = a.size();\n        vector&lt;vector&lt;ll&gt;&gt; result(n, vector&lt;ll&gt;(n));\n        for (int i = 0; i &lt; n; ++i) {\n            result[i][i] = 1;\n        }\n        return result;\n    } else if (n == 1) {\n        return a;\n    } else {\n        if ((n &amp; 1) == 0) {\n            vector&lt;vector&lt;ll&gt;&gt; a_square = modMul(a, a);\n            return fastPow(a_square, n \/ 2);\n        } else {\n            return modMul(a, fastPow(a, n - 1));\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Template<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"cpp\" class=\"language-cpp\">\/\/ m * n . n * l =&gt; m * l\nvector&lt;vector&lt;ll&gt;&gt; MatMul(vector&lt;vector&lt;ll&gt;&gt; const &amp;a, vector&lt;vector&lt;ll&gt;&gt; const &amp;b) {\n  int m = a.size();\n  int n = a[0].size();\n  int l = b[0].size();\n  vector&lt;vector&lt;ll&gt;&gt; res(m, vector&lt;ll&gt;(l));\n  for (int i = 0; i &lt; m; ++i) {\n    for (int j = 0; j &lt; l; ++j) {\n      for (int k = 0; k &lt; n; ++k) {\n        res[i][j] += a[i][k] * b[k][j];\n        res[i][j] %= kMod;\n      }\n    }\n  }\n  return res;\n}\n\nvector&lt;vector&lt;ll&gt;&gt; FastPower(vector&lt;vector&lt;ll&gt;&gt; const &amp;a, ll n) {\n  if (n == 0) {\n    int n = a.size();\n    vector&lt;vector&lt;ll&gt;&gt; result(n, vector&lt;ll&gt;(n));\n    for (int i = 0; i &lt; n; ++i) {\n        result[i][i] = 1;\n    }\n    return result;\n  } else if (n == 1) {\n      return a;\n  } else {\n      if ((n &amp; 1) == 0) {\n          vector&lt;vector&lt;ll&gt;&gt; a_square = MatMul(a, a);\n          return FastPower(a_square, n \/ 2);\n      } else {\n          return MatMul(a, FastPower(a, n - 1));\n      }\n  }\n}<\/code><\/pre>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary In this post, I will introduce a common technique in some DP counting problems: binary exponentiation. Typically, in these problems, you will be given a number n and you are asked to return the number of valid combinations. You need to figure out the initial state and the transform function between states. The problems&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[48,60,61],"tags":[],"class_list":["post-968","post","type-post","status-publish","format-standard","hentry","category-alg","category-dp-counting","category-dp-state-compression"],"_links":{"self":[{"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/posts\/968","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/comments?post=968"}],"version-history":[{"count":13,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/posts\/968\/revisions"}],"predecessor-version":[{"id":1606,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/posts\/968\/revisions\/1606"}],"wp:attachment":[{"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/media?parent=968"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/categories?post=968"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nanzhou.cc\/index.php\/wp-json\/wp\/v2\/tags?post=968"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}