|
28 | 28 | <meta property="og:description" content="P1004 [NOIP 2000 提高组] 方格取数 #走两次dp 如果只走一次,这题是非常经典的DP。但是要走两次,就变得非常有难度。 首先,可以简单地推广:要走两次,dp就存四个下标: int[][][][] dp = new int[N][N][N][N]; 我们只需要遍历所有可能,并且比较四种走法(同下、同右、一下一右),取最大值就可以了。 注意,一个数只能取一次,需要一个判断防止重复取"> |
29 | 29 | <meta property="og:locale" content="zh_CN"> |
30 | 30 | <meta property="article:published_time" content="2025-02-28T16:00:00.000Z"> |
31 | | -<meta property="article:modified_time" content="2025-03-08T01:17:51.150Z"> |
| 31 | +<meta property="article:modified_time" content="2025-03-09T06:20:42.079Z"> |
32 | 32 | <meta property="article:author" content="SIMULEITE"> |
33 | 33 | <meta property="article:tag" content="笔记"> |
34 | 34 | <meta name="twitter:card" content="summary"> |
|
141 | 141 | <div class="sidebar-panel-container"> |
142 | 142 | <!--noindex--> |
143 | 143 | <div class="post-toc-wrap sidebar-panel"> |
144 | | - <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#p1004-noip-2000-%E6%8F%90%E9%AB%98%E7%BB%84-%E6%96%B9%E6%A0%BC%E5%8F%96%E6%95%B0"><span class="nav-text"> P1004 [NOIP 2000 提高组] 方格取数</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#b3637-%E6%9C%80%E9%95%BF%E4%B8%8A%E5%8D%87%E5%AD%90%E5%BA%8F%E5%88%97"><span class="nav-text"> B3637 最长上升子序列</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#p2782-%E5%8F%8B%E5%A5%BD%E5%9F%8E%E5%B8%82"><span class="nav-text"> P2782 友好城市</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%B4%AA%E5%BF%83%E6%B3%95%E6%B1%82%E8%A7%A3lis"><span class="nav-text"> 贪心法求解LIS</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BC%98%E5%8C%96dp%E6%80%9D%E8%B7%AF%E4%BA%A4%E6%8D%A2%E7%8A%B6%E6%80%81%E4%B8%8E%E7%8A%B6%E6%80%81%E5%80%BC"><span class="nav-text"> 优化DP思路:交换状态与状态值</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#p1091-noip-2004-%E6%8F%90%E9%AB%98%E7%BB%84-%E5%90%88%E5%94%B1%E9%98%9F%E5%BD%A2"><span class="nav-text"> P1091 [NOIP 2004 提高组] 合唱队形</span></a></li></ol></div> |
| 144 | + <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#p1004-noip-2000-%E6%8F%90%E9%AB%98%E7%BB%84-%E6%96%B9%E6%A0%BC%E5%8F%96%E6%95%B0"><span class="nav-text"> P1004 [NOIP 2000 提高组] 方格取数</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#b3637-%E6%9C%80%E9%95%BF%E4%B8%8A%E5%8D%87%E5%AD%90%E5%BA%8F%E5%88%97"><span class="nav-text"> B3637 最长上升子序列</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#p2782-%E5%8F%8B%E5%A5%BD%E5%9F%8E%E5%B8%82"><span class="nav-text"> P2782 友好城市</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%B4%AA%E5%BF%83%E6%B3%95%E6%B1%82%E8%A7%A3lis"><span class="nav-text"> 贪心法求解LIS</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BC%98%E5%8C%96dp%E6%80%9D%E8%B7%AF%E4%BA%A4%E6%8D%A2%E7%8A%B6%E6%80%81%E4%B8%8E%E7%8A%B6%E6%80%81%E5%80%BC"><span class="nav-text"> 优化DP思路:交换状态与状态值</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#p1091-noip-2004-%E6%8F%90%E9%AB%98%E7%BB%84-%E5%90%88%E5%94%B1%E9%98%9F%E5%BD%A2"><span class="nav-text"> P1091 [NOIP 2004 提高组] 合唱队形</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#p1020-noip-1999-%E6%8F%90%E9%AB%98%E7%BB%84-%E5%AF%BC%E5%BC%B9%E6%8B%A6%E6%88%AA"><span class="nav-text"> P1020 [NOIP 1999 提高组] 导弹拦截</span></a></li></ol></div> |
145 | 145 | </div> |
146 | 146 | <!--/noindex--> |
147 | 147 |
|
@@ -223,7 +223,7 @@ <h1 class="post-title" itemprop="name headline"> |
223 | 223 | <i class="far fa-calendar-check"></i> |
224 | 224 | </span> |
225 | 225 | <span class="post-meta-item-text">更新于</span> |
226 | | - <time title="修改时间:2025-03-08 09:17:51" itemprop="dateModified" datetime="2025-03-08T09:17:51+08:00">2025-03-08</time> |
| 226 | + <time title="修改时间:2025-03-09 14:20:42" itemprop="dateModified" datetime="2025-03-09T14:20:42+08:00">2025-03-09</time> |
227 | 227 | </span> |
228 | 228 |
|
229 | 229 |
|
@@ -271,6 +271,15 @@ <h1 id="p1091-noip-2004-提高组-合唱队形"><a class="markdownIt-Anchor" hre |
271 | 271 | 合唱队形可以看成求两边LIS之和的最大值。此时总人数减去LIS之和的最大值,就是最少出列队员数。<br /> |
272 | 272 | 这里要注意当前index+1的值才是正确的长度。len标记的是数组的总长度,但是index会动态更新寻找更小值并做替换。当index找到最小值时,后面的更大值是在index以前的,不属于当前下标i+1结尾的IS长度。</p> |
273 | 273 | <figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="type">int</span>[] gdUp = <span class="keyword">new</span> <span class="title class_">int</span>[N];</span><br><span class="line"><span class="type">int</span> <span class="variable">lenUp</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"><span class="type">int</span>[] lenUps = <span class="keyword">new</span> <span class="title class_">int</span>[N];</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i < N; i += <span class="number">1</span>) {</span><br><span class="line"> <span class="type">int</span> <span class="variable">index</span> <span class="operator">=</span> lowerBound(gdUp, lenUp-<span class="number">1</span>, members[i]);</span><br><span class="line"> <span class="keyword">if</span> (index == lenUp) {</span><br><span class="line"> gdUp[lenUp++] = members[i];</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> gdUp[index] = members[i];</span><br><span class="line"> }</span><br><span class="line"> lenUps[i] = index + <span class="number">1</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">int</span>[] gdDown = <span class="keyword">new</span> <span class="title class_">int</span>[N];</span><br><span class="line"><span class="type">int</span> <span class="variable">lenDown</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"><span class="type">int</span>[] lenDowns = <span class="keyword">new</span> <span class="title class_">int</span>[N];</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> N-<span class="number">1</span>; i >= <span class="number">0</span>; i -= <span class="number">1</span>) {</span><br><span class="line"> <span class="type">int</span> <span class="variable">index</span> <span class="operator">=</span> lowerBound(gdDown, lenDown-<span class="number">1</span>, members[i]);</span><br><span class="line"> <span class="keyword">if</span> (index == lenDown) {</span><br><span class="line"> gdDown[lenDown++] = members[i];</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> gdDown[index] = members[i];</span><br><span class="line"> }</span><br><span class="line"> lenDowns[i] = index + <span class="number">1</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="variable">max</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i < N; i += <span class="number">1</span>) {</span><br><span class="line"> <span class="keyword">if</span> (lenUps[i] + lenDowns[i] - <span class="number">1</span> > max) {</span><br><span class="line"> max = lenUps[i] + lenDowns[i] - <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">System.out.println(N - max);</span><br></pre></td></tr></table></figure> |
| 274 | +<h1 id="p1020-noip-1999-提高组-导弹拦截"><a class="markdownIt-Anchor" href="#p1020-noip-1999-提高组-导弹拦截"></a> P1020 [NOIP 1999 提高组] 导弹拦截</h1> |
| 275 | +<p>#最长不递增子序列<br /> |
| 276 | +做这题各种WA让我非常confusing,仔细研究后发现是我没有理解导弹拦截的规则(可以拦截相等高度!),真所谓“失之毫厘,谬以千里”。原理其实很简单:</p> |
| 277 | +<ol> |
| 278 | +<li>导弹系统可以拦截的最多导弹数,是一个<strong>最长不严格递减子序列</strong>(导弹高度不需要严格递减、可以相等),在题目要求的数据规模下,必须使用贪心+二分解法,转化为逆序求<strong>最长不严格递增子序列</strong>。</li> |
| 279 | +<li>最少需要多少导弹拦截系统?一个系统只能拦截比前一个导弹高度更低的导弹,那么每出现一个比之前所有高度都更高的导弹,之前的系统都不能拦截。这就是LIS!</li> |
| 280 | +</ol> |
| 281 | +<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">{</span><br><span class="line"> ... <span class="comment">// 处理输入</span></span><br><span class="line"> </span><br><span class="line"> <span class="type">int</span>[] gdDown = <span class="keyword">new</span> <span class="title class_">int</span>[N];</span><br><span class="line"> <span class="type">int</span> <span class="variable">maxMissile</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> N-<span class="number">1</span>; i >= <span class="number">0</span>; i -= <span class="number">1</span>) {</span><br><span class="line"> <span class="type">int</span> <span class="variable">index</span> <span class="operator">=</span> upperBound(gdDown, maxMissile - <span class="number">1</span>, nums[i]);</span><br><span class="line"> <span class="keyword">if</span> (index == maxMissile) {</span><br><span class="line"> gdDown[maxMissile++] = nums[i];</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> gdDown[index] = nums[i];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="type">int</span>[] gdUp = <span class="keyword">new</span> <span class="title class_">int</span>[N];</span><br><span class="line"> <span class="type">int</span> <span class="variable">numSystems</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i < N; i += <span class="number">1</span>) {</span><br><span class="line"> <span class="type">int</span> <span class="variable">index</span> <span class="operator">=</span> lowerBound(gdUp, numSystems - <span class="number">1</span>, nums[i]);</span><br><span class="line"> <span class="keyword">if</span> (index == numSystems) {</span><br><span class="line"> gdUp[numSystems++] = nums[i];</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> gdUp[index] = nums[i];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> System.out.println(maxMissile + <span class="string">"\n"</span> + numSystems); </span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 找到第一个大于该数(不管有没有找到,允许gd里的数重复)的位置</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="type">int</span> <span class="title function_">upperBound</span><span class="params">(<span class="type">int</span>[] nums, <span class="type">int</span> end, <span class="type">int</span> target)</span> {</span><br><span class="line"> <span class="type">int</span> <span class="variable">start</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> (start <= end) {</span><br><span class="line"> <span class="type">int</span> <span class="variable">mid</span> <span class="operator">=</span> start + (end - start) / <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">if</span> (nums[mid] <= target) { </span><br><span class="line"> start = mid + <span class="number">1</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> end = mid - <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> start;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 找到第一个大于(没找到,在这个位置插入)/等于(找到,在这个位置替换)该数的位置</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="type">int</span> <span class="title function_">lowerBound</span><span class="params">(<span class="type">int</span>[] nums, <span class="type">int</span> end, <span class="type">int</span> target)</span> {</span><br><span class="line"> <span class="type">int</span> <span class="variable">start</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> (start <= end) {</span><br><span class="line"> <span class="type">int</span> <span class="variable">mid</span> <span class="operator">=</span> start + (end - start) / <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">if</span> (nums[mid] >= target) {</span><br><span class="line"> end = mid - <span class="number">1</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> start = mid + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> start;</span><br><span class="line">}</span><br></pre></td></tr></table></figure> |
| 282 | + |
274 | 283 | </div> |
275 | 284 |
|
276 | 285 |
|
|
0 commit comments