<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>game &#8211; Huahua&#8217;s Tech Road</title>
	<atom:link href="https://zxi.mytechroad.com/blog/tag/game/feed/" rel="self" type="application/rss+xml" />
	<link>https://zxi.mytechroad.com/blog</link>
	<description></description>
	<lastBuildDate>Fri, 02 Jan 2026 00:26:37 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.7.4</generator>

<image>
	<url>https://zxi.mytechroad.com/blog/wp-content/uploads/2017/09/cropped-photo-32x32.jpg</url>
	<title>game &#8211; Huahua&#8217;s Tech Road</title>
	<link>https://zxi.mytechroad.com/blog</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>轮回的载体：从红白机到NS2“Key卡”风波，看游戏介质的四十年战争</title>
		<link>https://zxi.mytechroad.com/blog/game/%e8%bd%ae%e5%9b%9e%e7%9a%84%e8%bd%bd%e4%bd%93%ef%bc%9a%e4%bb%8e%e7%ba%a2%e7%99%bd%e6%9c%ba%e5%88%b0ns2key%e5%8d%a1%e9%a3%8e%e6%b3%a2%ef%bc%8c%e7%9c%8b%e6%b8%b8%e6%88%8f%e4%bb%8b/</link>
					<comments>https://zxi.mytechroad.com/blog/game/%e8%bd%ae%e5%9b%9e%e7%9a%84%e8%bd%bd%e4%bd%93%ef%bc%9a%e4%bb%8e%e7%ba%a2%e7%99%bd%e6%9c%ba%e5%88%b0ns2key%e5%8d%a1%e9%a3%8e%e6%b3%a2%ef%bc%8c%e7%9c%8b%e6%b8%b8%e6%88%8f%e4%bb%8b/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Fri, 02 Jan 2026 00:10:27 +0000</pubDate>
				<category><![CDATA[Game]]></category>
		<category><![CDATA[cd]]></category>
		<category><![CDATA[game]]></category>
		<category><![CDATA[key card]]></category>
		<category><![CDATA[playstation]]></category>
		<category><![CDATA[switch]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=10532</guid>

					<description><![CDATA[前言：历史总是在押韵 前段时间，关于任天堂NS2“Key卡”模式的传闻闹得沸沸扬扬。所谓的Key卡，即实体卡带中不再包含完整游戏数据，仅存储启动授权（License Key）和少量引导文件，核心内容需通过网络下载。 玩家的愤怒可以理解——“我买了实体盘，却只买了个寂寞？”但如果你是经历过90年代PC游戏黄金期的老玩家，或许会会心一笑：这不就是当年的“Play Disc”吗？早在《星际争霸1》或《暗黑破坏神2》时代，我们不就是把游戏最大化安装到硬盘，CD光盘仅用来过DRM验证和播放CD音轨吗？ 从FC的卡带到PS的光盘，再到如今PS5的SSD，游戏介质的演变史，本质上是一场存储成本与读取速度之间的永恒博弈。今天，我们就来扒一扒这本跨越40年的技术账。 第一章 硅基的浪漫：卡带的黄金时代 (FC/SFC/GB/N64) 在那个电子游戏的洪荒年代，ROM卡带（Cartridge）是绝对的王者。 1.1 毫秒级的快乐 FC（红白机）时代的卡带，与其说是存储介质，不如说是主机硬件的一部分。当你插入《魂斗罗》时，你实际上是把额外的电路板插在了主板的总线上。 1.2 昂贵的代价 卡带的致命伤在于容量与成本（Mask ROM）。 第二章 光学的革命：容量的爆发与读盘的噩梦 (PS1/SS/PS2) 1994年，索尼PS1横空出世，通过CD-ROM彻底改变了游戏界。这场变革的核心逻辑是：用速度换容量，用廉价换市场。 2.1 650MB的震撼 一张CD拥有650MB-700MB的容量。这对当时最大只有几MB的卡带来说，简直是降维打击。 2.2&#8230;]]></description>
										<content:encoded><![CDATA[
<h1 class="wp-block-heading"><strong>前言：历史总是在押韵</strong></h1>



<p>前段时间，关于任天堂NS2“Key卡”模式的传闻闹得沸沸扬扬。所谓的Key卡，即实体卡带中不再包含完整游戏数据，仅存储启动授权（License Key）和少量引导文件，核心内容需通过网络下载。</p>



<p>玩家的愤怒可以理解——“我买了实体盘，却只买了个寂寞？”但如果你是经历过90年代PC游戏黄金期的老玩家，或许会会心一笑：这不就是当年的“Play Disc”吗？早在《星际争霸1》或《暗黑破坏神2》时代，我们不就是把游戏最大化安装到硬盘，CD光盘仅用来过DRM验证和播放CD音轨吗？</p>



<p>从FC的卡带到PS的光盘，再到如今PS5的SSD，游戏介质的演变史，本质上是一场<strong>存储成本</strong>与<strong>读取速度</strong>之间的永恒博弈。今天，我们就来扒一扒这本跨越40年的技术账。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading">第一章 硅基的浪漫：卡带的黄金时代 (FC/SFC/GB/N64)</h1>



<p>在那个电子游戏的洪荒年代，ROM卡带（Cartridge）是绝对的王者。</p>



<h2 class="wp-block-heading">1.1 毫秒级的快乐</h2>



<p>FC（红白机）时代的卡带，与其说是存储介质，不如说是主机硬件的一部分。当你插入《魂斗罗》时，你实际上是把额外的电路板插在了主板的总线上。</p>



<ul class="wp-block-list">
<li><strong>优点：</strong> 极致的读取速度。由于直接与CPU总线寻址，读取几乎是零延迟。没有“Loading”界面是那个时代最被低估的幸福。</li>



<li><strong>黑科技：</strong> 厂商可以在卡带里塞入特殊芯片。比如任天堂在SFC《星际火狐》卡带里塞了Super FX芯片来辅助3D运算，这在光盘时代是无法想象的。</li>
</ul>



<h2 class="wp-block-heading">1.2 昂贵的代价</h2>



<p>卡带的致命伤在于<strong>容量</strong>与<strong>成本</strong>（Mask ROM）。</p>



<ul class="wp-block-list">
<li><strong>容量瓶颈：</strong> FC游戏通常只有几百KB（比如《超级马里奥兄弟》只有40KB）。到了N64末期，最大容量也不过64MB（512Mbit）。</li>



<li><strong>价格高昂：</strong> 90年代一张正版卡带动辄400-600元人民币（按当时汇率），因为内存颗粒真的很贵。</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading">第二章 光学的革命：容量的爆发与读盘的噩梦 (PS1/SS/PS2)</h1>



<p>1994年，索尼PS1横空出世，通过CD-ROM彻底改变了游戏界。这场变革的核心逻辑是：<strong>用速度换容量，用廉价换市场</strong>。</p>



<h2 class="wp-block-heading">2.1 650MB的震撼</h2>



<p>一张CD拥有650MB-700MB的容量。这对当时最大只有几MB的卡带来说，简直是降维打击。</p>



<ul class="wp-block-list">
<li><strong>CG与音质：</strong> 因为有了海量空间，《最终幻想7》才能塞入大量的预渲染CG动画和高音质音乐。</li>



<li><strong>成本骤降：</strong> 压制一张光盘的成本不到1美元，而生产一盘卡带可能需要15-20美元。这让发行商赚得盆满钵满。</li>
</ul>



<h2 class="wp-block-heading">2.2 “Loading&#8230;”的恐惧</h2>



<p>光盘带来了巨大的副作用：<strong>寻道时间（Seek Time）</strong>。光头要在盘面上移动读取数据，导致了漫长的读盘时间。</p>



<ul class="wp-block-list">
<li><strong>PS1/PS2时代：</strong> 2倍速、4倍速光驱的读取速度仅为300KB/s &#8211; 600KB/s。</li>



<li><strong>噪音与磨损：</strong> 飞速旋转的电机声和划伤的光盘成为了玩家的新烦恼。</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading">第三章 混沌年代：混合模式与HDD的介入 (PS3/Xbox360/PC)</h1>



<p>进入高清时代，DVD的容量（4.7GB/8.5GB）开始捉襟见肘，蓝光（Blu-ray）登场。但此时，光驱读取速度已经跟不上游戏数据量的膨胀了。</p>



<h2 class="wp-block-heading">3.1 90年代的PC启示录（Key CD模式）</h2>



<p>由于早期CD光驱速度慢（1x/2x），而硬盘速度快，当时诞生了“最大化安装”。</p>



<ul class="wp-block-list">
<li><strong>机制：</strong> 游戏逻辑、贴图全部Copy到硬盘。</li>



<li><strong>光盘作用：</strong>
<ol start="1" class="wp-block-list">
<li><strong>Key（钥匙）：</strong> 防盗版验证。</li>



<li>CD Audio： 直接利用光驱播放CD音轨（节省CPU资源）。这就是如今“Key卡”模式的雏形。</li>
</ol>
</li>
</ul>



<h2 class="wp-block-heading">3.2 强制安装时代</h2>



<p>到了PS3和Xbox 360后期，以及PS4/PS5全世代，光盘实际上已经<strong>不再作为运行介质</strong>了。</p>



<ul class="wp-block-list">
<li><strong>现状：</strong> 当你把PS5的《战神：诸神黄昏》光盘插入机器，光驱会全速运转将数据“Copy”到SSD中。之后玩游戏时，光盘仅在启动时转动几秒钟验证License，随后便停止。</li>



<li><strong>本质：</strong> 现代光盘，就是一张<strong>存满离线安装包的Key卡</strong>。</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading">第四章 数据对比：卡带 vs 光盘 vs SSD</h1>



<p>为了直观展示介质的优缺点，我们来看一张详细的参数对比表：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><td><strong>世代/平台</strong></td><td><strong>核心介质</strong></td><td><strong>典型容量</strong></td><td><strong>最大读取速度</strong></td><td><strong>生产成本</strong></td><td><strong>玩家体验关键点</strong></td></tr></thead><tbody><tr><td><strong>FC (8-bit)</strong></td><td>Cartridge</td><td>40KB &#8211; 1MB</td><td>极快 (总线级)</td><td>高</td><td>插卡即玩，无加载，怕震动</td></tr><tr><td><strong>SFC (16-bit)</strong></td><td>Cartridge</td><td>512KB &#8211; 6MB</td><td>极快</td><td>极高</td><td>特殊芯片加持，价格昂贵</td></tr><tr><td><strong>PS1 (32-bit)</strong></td><td>CD-ROM</td><td>650MB &#8211; 700MB</td><td>~300KB/s (2x)</td><td>极低</td><td>海量CG，但读盘慢，易划伤</td></tr><tr><td><strong>PS2 (128-bit)</strong></td><td>DVD-ROM</td><td>4.7GB &#8211; 8.5GB</td><td>~5MB/s (4x)</td><td>低</td><td>依然受困于光驱速度</td></tr><tr><td><strong>PS3</strong></td><td>Blu-ray</td><td>25GB &#8211; 50GB</td><td>~9MB/s (2x)</td><td>中</td><td>强制安装开始普及</td></tr><tr><td><strong>Switch</strong></td><td>Game Card</td><td>4GB &#8211; 32GB</td><td>~100MB/s</td><td>高 (专利费)</td><td>回归卡带，便携，防苦味涂层</td></tr><tr><td><strong>PS5</strong></td><td>UHD BD</td><td>100GB</td><td><strong>仅作为安装盘</strong></td><td>低</td><td>SSD速度(5.5GB/s)接管一切</td></tr><tr><td><strong>NS2</strong></td><td>Game Card + Card (Key)</td><td>4GB &#8211; 64GB</td><td>～800MB/s</td><td>低 (如仅含Key)</td><td><strong>实体收藏 + 数字下载</strong></td></tr></tbody></table></figure>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading">第五章 现代困局：摩尔定律下的存储危机</h1>



<p>为什么NS2要搞“Key卡”？为什么3A大作越来越大？</p>



<h2 class="wp-block-heading">5.1 3A游戏的体积膨胀</h2>



<p>随着4K材质、无损音轨的普及，游戏体积呈指数级增长。</p>



<ul class="wp-block-list">
<li>《使命召唤》系列常年霸占150GB+。</li>



<li>《NBA 2K》系列动辄120GB。</li>
</ul>



<h2 class="wp-block-heading">5.2 Switch的“卡带税”痛点</h2>



<p>任天堂Switch重新启用卡带（闪存介质），虽然读取速度（约100MB/s）远快于光盘，但面临巨大的成本压力。</p>



<ul class="wp-block-list">
<li><strong>成本阶梯：</strong> 8GB卡带很便宜，16GB尚可，32GB成本陡增，64GB卡带更是天价。</li>



<li><strong>厂商对策：</strong> 为了省钱，很多第三方厂商（如2K Games）发行实体版时，只用8GB卡带装个开头，剩下50GB让你回家自己下载。这其实已经是“半Key卡”模式了。</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading">第六章 未来展望：Key卡作为收藏，下载作为常态</h1>



<p>对于未来的游戏发行<strong>“Key卡收藏 + 游戏下载”</strong>，不仅是趋势，更是解决“实体党”与“数字化”矛盾的最优解。</p>



<h2 class="wp-block-heading">6.1 为什么这种模式是必然？</h2>



<ol start="1" class="wp-block-list">
<li>解决首日补丁（Day 1 Patch）悖论：现在的实体光盘，里面刻录的是版本1.0。但往往游戏发售当天就有几十GB的1.01补丁。那张光盘里的数据在发售那一刻其实已经“过期”了。既然都要下载，何必执着于把完整数据压在盘里？</li>



<li>环保与成本的双赢：生产高容量闪存卡（如64GB/128GB）需要消耗大量半导体资源。如果实体卡只是一张精美的、带有NFC验证芯片的塑料片（类似Switch卡带，但容量极小），成本将大幅降低。厂商省钱，玩家买卡带也不用因为“卡带税”而比数字版贵。</li>



<li>满足收藏癖（Shelf Value）：玩家（包括我）买实体版，很多时候是为了那个盒子，为了把它摆在书架上。Key卡模式保留了封面、包装盒、说明书（如果有的话）以及一张可以拿在手里的“凭证”。</li>
</ol>



<h2 class="wp-block-heading">6.2 理想的“Key卡”形态</h2>



<p>我设想中完美的NS2实体卡应该具备以下特征：</p>



<ul class="wp-block-list">
<li><strong>只读存储区（几百MB）：</strong> 存储游戏的基础引导程序、离线授权Key、精美的电子说明书、原声OST。</li>



<li><strong>写入存储区（可选）：</strong> 允许玩家将自己的存档回写到卡带中（就像当年的记忆卡一样）。这样带着卡带去朋友家，既带了授权，也带了存档。</li>



<li><strong>即插即得：</strong> 插入卡带，系统自动触发下载。</li>
</ul>



<h2 class="wp-block-heading">6.3 潜在的风险与担忧</h2>



<p>当然，这种模式也有弊端，主要是<strong>游戏保存（Preservation）</strong>问题。</p>



<ul class="wp-block-list">
<li><strong>服务器关停：</strong> 20年后，当任天堂关闭了下载服务器，这张Key卡还能用吗？</li>



<li><strong>解决方案：</strong> 法律应规定，当官方服务器关闭时，Key卡应被解锁为“离线安装包”的解压密钥，允许玩家从第三方归档库合法安装。</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading">结语：从“拥有数据”到“拥有权利”</h1>



<p>从红白机时代手里沉甸甸的卡带，到未来可能只是一张轻飘飘的“Key卡”，我们“拥有”游戏的方式正在改变。</p>



<p>曾经，我们拥有的是数据的载体；</p>



<p>未来，我们拥有的将是数据的访问权和一份实体化的纪念品。</p>



<p>NS2推行Key卡模式，只要能把省下的卡带成本让利给玩家，并做好网络基础设施建设，这或许并不是坏事。毕竟，对于真正的玩家来说，最重要的永远是屏幕亮起那一刻，那是通往另一个世界的钥匙——无论这把钥匙是金做的，还是数据做的。</p>



<h1 class="wp-block-heading">附录 关于读盘速度</h1>



<p>回顾PS1和PS2时代，读盘速度慢通常由两个核心原因造成：</p>



<ol start="1" class="wp-block-list">
<li><strong>光驱本身的物理限制</strong>（PS1是2倍速CD，PS2是4倍速DVD），寻道时间（Seek Time）长。</li>



<li><strong>内存限制</strong>（PS1只有2MB主内存），导致无法一次性读取大量数据，必须频繁访问光盘。</li>
</ol>



<p>以下是几个教科书级别的“读盘地狱”案例，包含具体数据和体验描述：</p>



<h3 class="wp-block-heading">一、 PS1时代：2倍速光驱的噩梦</h3>



<p>PS1时代最痛苦的往往不是RPG（因为切图慢大家还能忍），而是<strong>从街机或卡带移植的动作/格斗游戏</strong>。这类游戏在街机/卡带上是零延迟的，到了光盘上就变成了灾难。</p>



<h4 class="wp-block-heading">1. 《合金弹头 1》 (Metal Slug) &#8211; PS1版</h4>



<ul class="wp-block-list">
<li><strong>现象：</strong> 切屏即读盘。</li>



<li><strong>数据：</strong> 每次关卡内切换场景（哪怕只是从这头走到那头），都需要 <strong>5-10秒</strong> 的“Now Loading”。</li>



<li><strong>体验：</strong> 在街机上行云流水的动作射击体验被切得支离破碎。你刚打完一波兵，想往前冲，屏幕黑了，右下角出现Loading字样。原本15分钟能通关的游戏，在PS1上因为读盘硬生生拖到了25分钟。</li>



<li><strong>原因：</strong> PS1内存仅2MB，存不下那么多精致的2D像素动画帧，必须打一段读一段。</li>
</ul>



<h4 class="wp-block-heading">2. 《拳皇 97》 (The King of Fighters &#8217;97) &#8211; PS1版</h4>



<ul class="wp-block-list">
<li><strong>现象：</strong> 回合制读盘。</li>



<li><strong>数据：</strong> 选人界面进入战斗需要 <strong>15秒+</strong>。最要命的是，每打赢一个人，换下一个对手上场时，需要读盘 <strong>10-12秒</strong>。</li>



<li><strong>体验：</strong> 3V3的对决，如果你把对面一穿三，你要看三次读盘画面。加上开场的Loading，一场几分钟的格斗，有一分半钟在看黑屏。</li>



<li><strong>对比：</strong> 土星（SS）版因为有额外的4MB加速卡（扩充内存），读盘几乎不可感；而PS1版简直是折磨。</li>
</ul>



<h4 class="wp-block-heading">3. 《时空之轮》 (Chrono Trigger) &#8211; PS1版 (收录于FF Chronicles)</h4>



<ul class="wp-block-list">
<li><strong>现象：</strong> 最著名的“反向移植”案例。</li>



<li><strong>数据：</strong>
<ul class="wp-block-list">
<li><strong>进入战斗：</strong> SFC版是瞬间进入；PS1版屏幕会黑并停顿 <strong>4-6秒</strong> 才能切入战斗画面。</li>



<li><strong>打开菜单：</strong> 按下菜单键，需要等 <strong>3-5秒</strong> 菜单才会弹出来。</li>
</ul>
</li>



<li><strong>体验：</strong> 这是一个在SFC卡带上“秒开”的游戏。到了机能更强的PS1上，因为光盘寻道机制，连打开背包都要读盘。这种<strong>高频次、短时间的卡顿</strong>比一次性长读取更搞心态。</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">二、 PS2时代：大容量带来的“长考”</h3>



<p>PS2虽然升级到了DVD，但游戏素材（纹理、模型、音频）的体积增长远超光驱速度的提升（仅4倍速）。</p>



<h4 class="wp-block-heading">1. 《古惑狼：由于科尔特斯的愤怒》 (Crash Bandicoot: The Wrath of Cortex) &#8211; 初版</h4>



<ul class="wp-block-list">
<li><strong>现象：</strong> PS2初期最著名的“读盘王”。</li>



<li><strong>数据：</strong> 进入一个普通关卡需要 <strong>40秒 到 60秒</strong>。</li>



<li><strong>体验：</strong> 在这将近一分钟的时间里，你只能看着主角Crash在屏幕中间做自由落体运动。考虑到这是一款动作游戏，玩家经常会死，死一次就要重新读盘或者读CheckPoint（也要很久），这种挫败感是毁灭性的。</li>



<li><strong>后续：</strong> 由于骂声太大，后来发行的“Greatest Hits”廉价版优化了文件结构，将读盘时间缩短到了20多秒。</li>
</ul>



<h4 class="wp-block-heading">2. 《模拟人生》 (The Sims) &#8211; PS2版</h4>



<ul class="wp-block-list">
<li><strong>现象：</strong> PC移植带来的水土不服。</li>



<li><strong>数据：</strong> 启动游戏进入家庭可能需要 <strong>2-3分钟</strong>。如果在游戏中去邻居家串门，或者切换到“购买/建造模式”，经常需要等待 <strong>30-45秒</strong>。</li>



<li><strong>体验：</strong> 这个游戏本来就需要频繁切换模式。由于读盘太慢，很多玩家干脆不装修房子了，或者不敢出门社交，硬生生玩成了“宅男模拟器”。</li>
</ul>



<h4 class="wp-block-heading">3. 《WWE SmackDown! vs. Raw 2006》</h4>



<ul class="wp-block-list">
<li><strong>现象：</strong> 漫长的赛前准备。</li>



<li><strong>数据：</strong> 这种体育类游戏，由于要加载几名摔角手的高精度模型、出场动画、专属音乐、场馆观众。一场比赛开始前的总读盘时间（包含出场）往往超过 <strong>1分半钟</strong>。</li>



<li><strong>体验：</strong> loading条也是出了名的慢，经常卡在90%不动，让人怀疑死机了。</li>
</ul>



<h4 class="wp-block-heading">4. 《侠盗猎车手：圣安地列斯》 (GTA: SA) &#8211; 地图流送问题</h4>



<ul class="wp-block-list">
<li><strong>现象：</strong> 这是一个特殊的例子，它没有Loading画面，但它<strong>读盘慢到跟不上游戏速度</strong>。</li>



<li><strong>数据/体验：</strong> 当你驾驶战斗机（Hydra）在低空全速飞行时，PS2的光驱读盘速度跟不上地图数据的加载速度。</li>



<li><strong>结果：</strong> 你会飞进一片模糊的色块中，或者直接撞上一栋<strong>还没加载出来的透明大楼</strong>。这就是典型的光驱读取瓶颈（Streaming Latency）。</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">三、 数据总结表：为什么卡带/SSD是神</h3>



<p>我们可以对比一下这些操作在不同介质上的大致耗时：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><td><strong>操作场景</strong></td><td><strong>FC/SFC/N64 (卡带)</strong></td><td><strong>PS1/PS2 (光盘)</strong></td><td><strong>PS5/XSX (NVMe SSD)</strong></td></tr></thead><tbody><tr><td><strong>打开系统菜单</strong></td><td>&lt; 0.1秒 (瞬间)</td><td>3 &#8211; 5秒 (甚至更久)</td><td>&lt; 0.1秒</td></tr><tr><td><strong>进入战斗/关卡</strong></td><td>&lt; 1秒</td><td>15 &#8211; 60秒</td><td>1 &#8211; 3秒</td></tr><tr><td><strong>死亡重开</strong></td><td>&lt; 0.5秒</td><td>10 &#8211; 40秒</td><td>&lt; 1秒</td></tr><tr><td><strong>高速移动中加载地图</strong></td><td>无感</td><td>贴图模糊/物体消失</td><td>无感</td></tr></tbody></table></figure>



<p>光盘时代虽然带来了大容量和多媒体盛宴，但在<strong>“即时反馈”</strong>这一游戏核心体验上，实际上是倒退的。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/game/%e8%bd%ae%e5%9b%9e%e7%9a%84%e8%bd%bd%e4%bd%93%ef%bc%9a%e4%bb%8e%e7%ba%a2%e7%99%bd%e6%9c%ba%e5%88%b0ns2key%e5%8d%a1%e9%a3%8e%e6%b3%a2%ef%bc%8c%e7%9c%8b%e6%b8%b8%e6%88%8f%e4%bb%8b/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>逆转裁判 Ace Attorney &#124; GBA遮罩 Overlay &#124; RG556</title>
		<link>https://zxi.mytechroad.com/blog/game/ace-attorney-gba-overlay-rg556/</link>
					<comments>https://zxi.mytechroad.com/blog/game/ace-attorney-gba-overlay-rg556/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Mon, 10 Feb 2025 16:45:32 +0000</pubDate>
				<category><![CDATA[Game]]></category>
		<category><![CDATA[ace attorney]]></category>
		<category><![CDATA[game]]></category>
		<category><![CDATA[gba]]></category>
		<category><![CDATA[overlay]]></category>
		<category><![CDATA[retro game]]></category>
		<category><![CDATA[retroarch]]></category>
		<category><![CDATA[逆转裁判]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=10193</guid>

					<description><![CDATA[最近在玩《逆转裁判》，在iOS上买了合集 Ace Attorney Trilogy（花了我$24.99大洋呢，今天降到$14.99了）。虽然画面重绘过了，高清了不少，官方中文版也加入了中文语音(异议!)，但本人不太喜欢搓玻璃，所以又开始倒腾模拟器，手上有周哥的RG35XX H和RG556（悄悄说RG34XX还在路上，不过它就不用遮罩了）。给556做了个遮罩（其实就是张图片，PS水平实在有限），应该也适用于其他1920&#215;1080，GBA 6倍点对点的屏幕，只考虑掌机，所以没有加按钮，喜欢的可以自行拿走。 效果预览 Update: 2/24/2025 1-3终于全部通关了，最后一个故事太精彩了！送上几幅截屏，给这段旅程画上一个顿号。]]></description>
										<content:encoded><![CDATA[
<p>最近在玩《逆转裁判》，在iOS上买了合集<a href="https://apps.apple.com/us/app/ace-attorney-trilogy/id1621065119"> Ace Attorney Trilogy</a>（花了我$24.99大洋呢，今天降到$14.99了）。虽然画面重绘过了，高清了不少，官方中文版也加入了中文语音(异议!)，但本人不太喜欢搓玻璃，所以又开始倒腾模拟器，手上有周哥的<a href="https://amzn.to/40QRQhS">RG35XX H</a>和<a href="https://amzn.to/4aVN5Il">RG556</a>（悄悄说<a href="https://amzn.to/40MbMCy">RG34XX</a>还在路上，不过它就不用遮罩了）。给556做了个遮罩（其实就是张图片，PS水平实在有限），应该也适用于其他1920&#215;1080，GBA 6倍点对点的屏幕，只考虑掌机，所以没有加按钮，喜欢的可以自行拿走。</p>



<div class="wp-block-file"><a id="wp-block-file--media-8c8c71e6-7126-4c3c-98c4-a79c2bd3e5c5" href="https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/gba_ace_attorney.zip">gba_ace_attorney_overlay</a><a href="https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/gba_ace_attorney.zip" class="wp-block-file__button" download aria-describedby="wp-block-file--media-8c8c71e6-7126-4c3c-98c4-a79c2bd3e5c5">Download</a></div>



<p>效果预览</p>



<figure class="wp-block-image size-large"><a href="https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/Screenshot_20250210-081645.png"><img fetchpriority="high" decoding="async" width="1024" height="576" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/Screenshot_20250210-081645-1024x576.png" alt="" class="wp-image-10195" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/Screenshot_20250210-081645-1024x576.png 1024w, https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/Screenshot_20250210-081645-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/Screenshot_20250210-081645-768x432.png 768w, https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/Screenshot_20250210-081645-1536x864.png 1536w, https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/Screenshot_20250210-081645.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px" /></a><figcaption>截屏</figcaption></figure>



<figure class="wp-block-image size-large"><a href="https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/IMG_1335.jpg"><img decoding="async" width="1024" height="768" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/IMG_1335-1024x768.jpg" alt="" class="wp-image-10194" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/IMG_1335-1024x768.jpg 1024w, https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/IMG_1335-300x225.jpg 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/IMG_1335-768x576.jpg 768w, https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/IMG_1335.jpg 1331w" sizes="(max-width: 1024px) 100vw, 1024px" /></a><figcaption>实机拍摄</figcaption></figure>



<p>Update: 2/24/2025</p>



<p>1-3终于全部通关了，最后一个故事太精彩了！送上几幅截屏，给这段旅程画上一个顿号。</p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter size-full"><a href="https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/Screenshot_20250224-155445.png"><img decoding="async" width="640" height="360" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/Screenshot_20250224-155445.png" alt="" class="wp-image-10202" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/Screenshot_20250224-155445.png 640w, https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/Screenshot_20250224-155445-300x169.png 300w" sizes="(max-width: 640px) 100vw, 640px" /></a><figcaption>罐子其实在真宵小时候就被打破过～</figcaption></figure></div>

<div class="wp-block-image">
<figure class="aligncenter size-full"><a href="https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/Screenshot_20250224-160328.png"><img loading="lazy" decoding="async" width="640" height="360" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/Screenshot_20250224-160328.png" alt="" class="wp-image-10204" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/Screenshot_20250224-160328.png 640w, https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/Screenshot_20250224-160328-300x169.png 300w" sizes="auto, (max-width: 640px) 100vw, 640px" /></a><figcaption>全家福</figcaption></figure></div>

<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><a href="https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/Screenshot_20250224-160337.png"><img loading="lazy" decoding="async" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/Screenshot_20250224-160337.png" alt="" class="wp-image-10205" width="634" height="356" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/Screenshot_20250224-160337.png 634w, https://zxi.mytechroad.com/blog/wp-content/uploads/2025/02/Screenshot_20250224-160337-300x168.png 300w" sizes="auto, (max-width: 634px) 100vw, 634px" /></a><figcaption>三人组</figcaption></figure></div>]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/game/ace-attorney-gba-overlay-rg556/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 1872. Stone Game VIII</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-1872-stone-game-viii/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-1872-stone-game-viii/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Fri, 06 Aug 2021 05:59:36 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[game]]></category>
		<category><![CDATA[hard]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=8494</guid>

					<description><![CDATA[Alice and Bob take turns playing a game, with&#160;Alice starting first. There are&#160;n&#160;stones arranged in a row. On each player&#8217;s turn, while the number of&#8230;]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="花花酱 LeetCode 1872. Stone Game VIII - 刷题找工作 EP394" width="500" height="281" src="https://www.youtube.com/embed/5EaopigkqUc?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>Alice and Bob take turns playing a game, with&nbsp;<strong>Alice starting first</strong>.</p>



<p>There are&nbsp;<code>n</code>&nbsp;stones arranged in a row. On each player&#8217;s turn, while the number of stones is&nbsp;<strong>more than one</strong>, they will do the following:</p>



<ol class="wp-block-list"><li>Choose an integer&nbsp;<code>x &gt; 1</code>, and&nbsp;<strong>remove</strong>&nbsp;the leftmost&nbsp;<code>x</code>&nbsp;stones from the row.</li><li>Add the&nbsp;<strong>sum</strong>&nbsp;of the&nbsp;<strong>removed</strong>&nbsp;stones&#8217; values to the player&#8217;s score.</li><li>Place a&nbsp;<strong>new stone</strong>, whose value is equal to that sum, on the left side of the row.</li></ol>



<p>The game stops when&nbsp;<strong>only</strong>&nbsp;<strong>one</strong>&nbsp;stone is left in the row.</p>



<p>The&nbsp;<strong>score difference</strong>&nbsp;between Alice and Bob is&nbsp;<code>(Alice's score - Bob's score)</code>. Alice&#8217;s goal is to&nbsp;<strong>maximize</strong>&nbsp;the score difference, and Bob&#8217;s goal is the&nbsp;<strong>minimize</strong>&nbsp;the score difference.</p>



<p>Given an integer array&nbsp;<code>stones</code>&nbsp;of length&nbsp;<code>n</code>&nbsp;where&nbsp;<code>stones[i]</code>&nbsp;represents the value of the&nbsp;<code>i<sup>th</sup></code>&nbsp;stone&nbsp;<strong>from the left</strong>, return&nbsp;<em>the&nbsp;<strong>score difference</strong>&nbsp;between Alice and Bob if they both play&nbsp;<strong>optimally</strong>.</em></p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> stones = [-1,2,-3,4,-5]
<strong>Output:</strong> 5
<strong>Explanation:</strong>
- Alice removes the first 4 stones, adds (-1) + 2 + (-3) + 4 = 2 to her score, and places a stone of
  value 2 on the left. stones = [2,-5].
- Bob removes the first 2 stones, adds 2 + (-5) = -3 to his score, and places a stone of value -3 on
  the left. stones = [-3].
The difference between their scores is 2 - (-3) = 5.
</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> stones = [7,-6,5,10,5,-2,-6]
<strong>Output:</strong> 13
<strong>Explanation:</strong>
- Alice removes all stones, adds 7 + (-6) + 5 + 10 + 5 + (-2) + (-6) = 13 to her score, and places a
  stone of value 13 on the left. stones = [13].
The difference between their scores is 13 - 0 = 13.
</pre>



<p><strong>Example 3:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> stones = [-10,-12]
<strong>Output:</strong> -22
<strong>Explanation:</strong>
- Alice can only make one move, which is to remove both stones. She adds (-10) + (-12) = -22 to her
  score and places a stone of value -22 on the left. stones = [-22].
The difference between their scores is (-22) - 0 = -22.
</pre>



<p><strong>Constraints:</strong></p>



<ul class="wp-block-list"><li><code>n == stones.length</code></li><li><code>2 &lt;= n &lt;= 10<sup>5</sup></code></li><li><code>-10<sup>4</sup>&nbsp;&lt;= stones[i] &lt;= 10<sup>4</sup></code></li></ul>



<h2 class="wp-block-heading"><strong>Solution: Prefix Sum + DP</strong></h2>



<figure class="wp-block-image size-large"><a href="https://zxi.mytechroad.com/blog/wp-content/uploads/2021/08/1872-ep393-1.png"><img loading="lazy" decoding="async" width="960" height="540" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2021/08/1872-ep393-1.png" alt="" class="wp-image-8513" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2021/08/1872-ep393-1.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2021/08/1872-ep393-1-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2021/08/1872-ep393-1-768x432.png 768w" sizes="auto, (max-width: 960px) 100vw, 960px" /></a></figure>



<figure class="wp-block-image size-large"><a href="https://zxi.mytechroad.com/blog/wp-content/uploads/2021/08/1872-ep393-2.png"><img loading="lazy" decoding="async" width="960" height="540" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2021/08/1872-ep393-2.png" alt="" class="wp-image-8514" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2021/08/1872-ep393-2.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2021/08/1872-ep393-2-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2021/08/1872-ep393-2-768x432.png 768w" sizes="auto, (max-width: 960px) 100vw, 960px" /></a></figure>



<figure class="wp-block-image size-large"><a href="https://zxi.mytechroad.com/blog/wp-content/uploads/2021/08/1872-ep393-3.png"><img loading="lazy" decoding="async" width="960" height="540" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2021/08/1872-ep393-3.png" alt="" class="wp-image-8515" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2021/08/1872-ep393-3.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2021/08/1872-ep393-3-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2021/08/1872-ep393-3-768x432.png 768w" sizes="auto, (max-width: 960px) 100vw, 960px" /></a></figure>



<figure class="wp-block-image size-large"><a href="https://zxi.mytechroad.com/blog/wp-content/uploads/2021/08/1872-ep393-4-1.png"><img loading="lazy" decoding="async" width="960" height="540" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2021/08/1872-ep393-4-1.png" alt="" class="wp-image-8518" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2021/08/1872-ep393-4-1.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2021/08/1872-ep393-4-1-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2021/08/1872-ep393-4-1-768x432.png 768w" sizes="auto, (max-width: 960px) 100vw, 960px" /></a></figure>



<p>Note: Naive DP (min-max) takes O(n<sup>2</sup>) which leads to TLE. The key of this problem is that each player takes k stones, but put their sum back as a new stone, so you can assume <strong>all the original</strong> stones are still there, but opponent has to start from the k+1 th stone.</p>



<p>Let dp[i] denote the max score diff that current player can achieve by taking stones[0~i] (or equivalent)</p>



<p>dp[n-1] = sum(A[0~n-1]) // Alice takes all the stones.<br>dp[n-2] = sum(A[0~n-2]) &#8211; (A[n-1] + sum(A[0~n-2])) = sum(A[0~n-2]) &#8211; dp[n-1] // Alice takes n-1 stones, Bob take the last one (A[n-1]) + put-back-stone.<br>dp[n-3] = sum(A[0~n-3]) &#8211; max(dp[n-2], dp[n-1]) // Alice takes n-2 stones, Bob has two options (takes n-1 stones or takes n stones)<br>&#8230;<br>dp[0] = A[0] &#8211; max(dp[n-1], dp[n-1], &#8230;, dp[1]) // Alice takes the first stone, Bob has n-1 options.</p>



<p>Time complexity: O(n)<br>Space complexity: O(1)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class Solution {
public:
  int stoneGameVIII(vector&lt;int&gt;&amp; stones) {
    const int n = stones.size();
    for (int i = 1; i &lt; n; ++i)
      stones[i] += stones[i - 1];
    int ans = stones.back(); // take all the stones.
    for (int i = n - 2; i &gt; 0; --i)
      ans = max(ans, stones[i] - ans);
    return ans;
  }
};</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-1872-stone-game-viii/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 1690. Stone Game VII</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-1690-stone-game-vii/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-1690-stone-game-vii/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 13 Dec 2020 22:25:07 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[game]]></category>
		<category><![CDATA[medium]]></category>
		<category><![CDATA[minmax]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=7808</guid>

					<description><![CDATA[Alice and Bob take turns playing a game, with&#160;Alice starting first. There are&#160;n&#160;stones arranged in a row. On each player&#8217;s turn, they can&#160;remove&#160;either the leftmost&#8230;]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="花花酱 LeetCode 1690. Stone Game VII - 刷题找工作 EP375" width="500" height="281" src="https://www.youtube.com/embed/RVWDJye4kJA?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>Alice and Bob take turns playing a game, with&nbsp;<strong>Alice starting first</strong>.</p>



<p>There are&nbsp;<code>n</code>&nbsp;stones arranged in a row. On each player&#8217;s turn, they can&nbsp;<strong>remove</strong>&nbsp;either the leftmost stone or the rightmost stone from the row and receive points equal to the&nbsp;<strong>sum</strong>&nbsp;of the remaining stones&#8217; values in the row. The winner is the one with the higher score when there are no stones left to remove.</p>



<p>Bob found that he will always lose this game (poor Bob, he always loses), so he decided to&nbsp;<strong>minimize the score&#8217;s difference</strong>. Alice&#8217;s goal is to&nbsp;<strong>maximize the difference</strong>&nbsp;in the score.</p>



<p>Given an array of integers&nbsp;<code>stones</code>&nbsp;where&nbsp;<code>stones[i]</code>&nbsp;represents the value of the&nbsp;<code>i<sup>th</sup></code>&nbsp;stone&nbsp;<strong>from the left</strong>, return&nbsp;<em>the&nbsp;<strong>difference</strong>&nbsp;in Alice and Bob&#8217;s score if they both play&nbsp;<strong>optimally</strong>.</em></p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> stones = [5,3,1,4,2]
<strong>Output:</strong> 6
<strong>Explanation:</strong> 
- Alice removes 2 and gets 5 + 3 + 1 + 4 = 13 points. Alice = 13, Bob = 0, stones = [5,3,1,4].
- Bob removes 5 and gets 3 + 1 + 4 = 8 points. Alice = 13, Bob = 8, stones = [3,1,4].
- Alice removes 3 and gets 1 + 4 = 5 points. Alice = 18, Bob = 8, stones = [1,4].
- Bob removes 1 and gets 4 points. Alice = 18, Bob = 12, stones = [4].
- Alice removes 4 and gets 0 points. Alice = 18, Bob = 12, stones = [].
The score difference is 18 - 12 = 6.
</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> stones = [7,90,5,1,100,10,10,2]
<strong>Output:</strong> 122</pre>



<p><strong>Constraints:</strong></p>



<ul class="wp-block-list"><li><code>n == stones.length</code></li><li><code>2 &lt;= n &lt;= 1000</code></li><li><code>1 &lt;= stones[i] &lt;= 1000</code></li></ul>



<h2 class="wp-block-heading"><strong>Solution: MinMax + DP</strong></h2>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="960" height="540" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2020/12/1690-ep375.png" alt="" class="wp-image-7817" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2020/12/1690-ep375.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2020/12/1690-ep375-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2020/12/1690-ep375-768x432.png 768w" sizes="auto, (max-width: 960px) 100vw, 960px" /></figure>



<p>For a sub game of stones[l~r] game(l, r), we have two choices:<br>Remove the left one: sum(stones[l + 1 ~ r]) &#8211; game(l + 1, r)<br>Remove the right one: sum(stones[l ~ r &#8211; 1]) &#8211; game(l, r &#8211; 1)<br>And take the best choice.</p>



<p>Time complexity: O(n^2)<br>Space complexity: O(n^2)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++/Top Down</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class Solution {
public:
  int stoneGameVII(vector&lt;int&gt;&amp; A) {
    const int n = A.size();
    vector&lt;vector&lt;int&gt;&gt; cache(n, vector&lt;int&gt;(n, INT_MAX));
    function&lt;int(int, int, int)&gt; dp = [&amp;](int l, int r, int s) {
      if (l &gt;= r) return 0;
      if (cache[l][r] == INT_MAX)
        cache[l][r] = max(s - A[r] - dp(l, r - 1, s - A[r]),
                          s - A[l] - dp(l + 1, r, s - A[l]));
      return cache[l][r];
    };
    return dp(0, n - 1, accumulate(begin(A), end(A), 0));
  }
};</pre>

</div><h2 class="tabtitle">C++/Bottom-Up</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class Solution {
public:
  int stoneGameVII(vector&lt;int&gt;&amp; A) {
    const int n = A.size();
    vector&lt;int&gt; s(n + 1);
    for (int i = 0; i &lt; n; ++i) s[i + 1] = s[i] + A[i];
    vector&lt;vector&lt;int&gt;&gt; dp(n, vector&lt;int&gt;(n, 0));
    for (int c = 2; c &lt;= n; ++c)
      for (int l = 0, r = l + c - 1; r &lt; n; ++l, ++r)
        dp[l][r] = max(s[r + 1] - s[l + 1] - dp[l + 1][r],
                       s[r] - s[l] - dp[l][r - 1]);
    return dp[0][n - 1];
  }
};</pre>

</div><h2 class="tabtitle">Python3</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag"># Author: Huahua
class Solution:
  def stoneGameVII(self, stones: List[int]) -&gt; int:
    n = len(stones)
    s = [0] * (n + 1)
    for i in range(n): s[i + 1] = s[i] + stones[i]
    dp = [[0] * n for _ in range(n)]
    for c in range(2, n + 1):
      for l in range(0, n - c + 1):
        r = l + c - 1
        dp[l][r] = max(s[r + 1] - s[l + 1] - dp[l + 1][r],
                       s[r] - s[l] - dp[l][r - 1])
    return dp[0][n - 1]</pre>
</div></div>



<h2 class="wp-block-heading"><strong>Related Problems</strong></h2>



<ul class="wp-block-list"><li><a href="https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-877-stone-game/">https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-877-stone-game/</a></li><li><a href="https://zxi.mytechroad.com/blog/recursion/leetcode-1140-stone-game-ii/">https://zxi.mytechroad.com/blog/recursion/leetcode-1140-stone-game-ii/</a></li><li><a href="https://zxi.mytechroad.com/blog/game-theory/leetcode-1406-stone-game-iii/">https://zxi.mytechroad.com/blog/game-theory/leetcode-1406-stone-game-iii/</a></li><li><a href="https://zxi.mytechroad.com/blog/game-theory/leetcode-1510-stone-game-iv/">https://zxi.mytechroad.com/blog/game-theory/leetcode-1510-stone-game-iv/</a></li><li><a href="https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-1563-stone-game-v/">https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-1563-stone-game-v/</a></li><li><a href="https://zxi.mytechroad.com/blog/greedy/leetcode-1686-stone-game-vi/">https://zxi.mytechroad.com/blog/greedy/leetcode-1686-stone-game-vi/</a></li></ul>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-1690-stone-game-vii/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 1686. Stone Game VI</title>
		<link>https://zxi.mytechroad.com/blog/greedy/leetcode-1686-stone-game-vi/</link>
					<comments>https://zxi.mytechroad.com/blog/greedy/leetcode-1686-stone-game-vi/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 13 Dec 2020 07:35:13 +0000</pubDate>
				<category><![CDATA[Greedy]]></category>
		<category><![CDATA[game]]></category>
		<category><![CDATA[greedy]]></category>
		<category><![CDATA[medium]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=7793</guid>

					<description><![CDATA[Alice and Bob take turns playing a game, with Alice starting first. There are&#160;n&#160;stones in a pile. On each player&#8217;s turn, they can&#160;remove&#160;a stone from&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Alice and Bob take turns playing a game, with Alice starting first.</p>



<p>There are&nbsp;<code>n</code>&nbsp;stones in a pile. On each player&#8217;s turn, they can&nbsp;<strong>remove</strong>&nbsp;a stone from the pile and receive points based on the stone&#8217;s value. Alice and Bob may&nbsp;<strong>value the stones differently</strong>.</p>



<p>You are given two integer arrays of length&nbsp;<code>n</code>,&nbsp;<code>aliceValues</code>&nbsp;and&nbsp;<code>bobValues</code>. Each&nbsp;<code>aliceValues[i]</code>&nbsp;and&nbsp;<code>bobValues[i]</code>&nbsp;represents how Alice and Bob, respectively, value the&nbsp;<code>i<sup>th</sup></code>&nbsp;stone.</p>



<p>The winner is the person with the most points after all the stones are chosen. If both players have the same amount of points, the game results in a draw. Both players will play&nbsp;<strong>optimally</strong>.</p>



<p>Determine the result of the game, and:</p>



<ul class="wp-block-list"><li>If Alice wins, return&nbsp;<code>1</code>.</li><li>If Bob wins, return&nbsp;<code>-1</code>.</li><li>If the game results in a draw, return&nbsp;<code>0</code>.</li></ul>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> aliceValues = [1,3], bobValues = [2,1]
<strong>Output:</strong> 1
<strong>Explanation:</strong>
If Alice takes stone 1 (0-indexed) first, Alice will receive 3 points.
Bob can only choose stone 0, and will only receive 2 points.
Alice wins.
</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> aliceValues = [1,2], bobValues = [3,1]
<strong>Output:</strong> 0
<strong>Explanation:</strong>
If Alice takes stone 0, and Bob takes stone 1, they will both have 1 point.
Draw.
</pre>



<p><strong>Example 3:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> aliceValues = [2,4,3], bobValues = [1,6,7]
<strong>Output:</strong> -1
<strong>Explanation:</strong>
Regardless of how Alice plays, Bob will be able to have more points than Alice.
For example, if Alice takes stone 1, Bob can take stone 2, and Alice takes stone 0, Alice will have 6 points to Bob's 7.
Bob wins.
</pre>



<p><strong>Constraints:</strong></p>



<ul class="wp-block-list"><li><code>n == aliceValues.length == bobValues.length</code></li><li><code>1 &lt;= n &lt;= 10<sup>5</sup></code></li><li><code>1 &lt;= aliceValues[i], bobValues[i] &lt;= 100</code></li></ul>



<h2 class="wp-block-heading"><strong>Solution: Greedy</strong></h2>



<p>Sort by the sum of stone values.</p>



<p>Time complexity: O(nlogn)<br>Space complexity: O(n)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class Solution {
public:
  int stoneGameVI(vector&lt;int&gt;&amp; A, vector&lt;int&gt;&amp; B) {
    const int n = A.size();
    vector&lt;pair&lt;int, int&gt;&gt; s(n);    
    for (int i = 0; i &lt; n; ++i)
      s.emplace_back(A[i] + B[i], i);
    sort(rbegin(s), rend(s));
    int ans = 0;
    for (int i = 0; i &lt; n; ++i) {
      int idx = s[i].second;
      ans += (i &amp; 1 ? B[idx] : A[idx]) * (i &amp; 1 ? -1 : 1);
    }
    return ans &lt; 0 ? -1 : (ans &gt; 0);
  }
};</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/greedy/leetcode-1686-stone-game-vi/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 1510. Stone Game IV</title>
		<link>https://zxi.mytechroad.com/blog/game-theory/leetcode-1510-stone-game-iv/</link>
					<comments>https://zxi.mytechroad.com/blog/game-theory/leetcode-1510-stone-game-iv/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Fri, 17 Jul 2020 15:37:43 +0000</pubDate>
				<category><![CDATA[Game Theory]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[game]]></category>
		<category><![CDATA[hard]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=7107</guid>

					<description><![CDATA[Alice and Bob take turns playing a game, with Alice starting first. Initially, there are&#160;n&#160;stones in a pile.&#160; On each player&#8217;s turn, that player makes&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Alice and Bob take turns playing a game, with Alice starting first.</p>



<p>Initially, there are&nbsp;<code>n</code>&nbsp;stones in a pile.&nbsp; On each player&#8217;s turn, that player makes a&nbsp;<em>move</em>&nbsp;consisting of removing&nbsp;<strong>any</strong>&nbsp;non-zero&nbsp;<strong>square number</strong>&nbsp;of stones in the pile.</p>



<p>Also, if a player cannot make a move, he/she loses the game.</p>



<p>Given a positive&nbsp;integer&nbsp;<code>n</code>.&nbsp;Return&nbsp;<code>True</code>&nbsp;if and only if Alice wins the game otherwise return&nbsp;<code>False</code>, assuming both players play optimally.</p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 1
<strong>Output:</strong> true
<strong>Explanation: </strong>Alice can remove 1 stone winning the game because Bob doesn't have any moves.</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 2
<strong>Output:</strong> false
<strong>Explanation: </strong>Alice can only remove 1 stone, after that Bob removes the last one winning the game (2 -&gt; 1 -&gt; 0).</pre>



<p><strong>Example 3:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 4
<strong>Output:</strong> true
<strong>Explanation:</strong> n is already a perfect square, Alice can win with one move, removing 4 stones (4 -&gt; 0).
</pre>



<p><strong>Example 4:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 7
<strong>Output:</strong> false
<strong>Explanation: </strong>Alice can't win the game if Bob plays optimally.
If Alice starts removing 4 stones, Bob will remove 1 stone then Alice should remove only 1 stone and finally Bob removes the last one (7 -&gt; 3 -&gt; 2 -&gt; 1 -&gt; 0). 
If Alice starts removing 1 stone, Bob will remove 4 stones then Alice only can remove 1 stone and finally Bob removes the last one (7 -&gt; 6 -&gt; 2 -&gt; 1 -&gt; 0).</pre>



<p><strong>Example 5:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> n = 17
<strong>Output:</strong> false
<strong>Explanation: </strong>Alice can't win the game if Bob plays optimally.
</pre>



<p><strong>Constraints:</strong></p>



<ul class="wp-block-list"><li><code>1 &lt;= n &lt;= 10^5</code></li></ul>



<h2 class="wp-block-heading"><strong>Solution: Recursion w/ Memoization / DP</strong></h2>



<p>Let win(n) denotes whether the current play will win or not.<br>Try all possible square numbers and see whether the other player will lose or not.<br>win(n) = any(win(n &#8211; i*i) == False) ? True : False<br>base case: win(0) = False</p>



<p>Time complexity: O(nsqrt(n))<br>Space complexity: O(n)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag">class Solution {
public:
  bool winnerSquareGame(int n) {    
    vector&lt;int&gt; cache(n + 1, 0); // 0:Unknown, 1:Win, -1:Lose
    function&lt;int(int)&gt; win = [&amp;](int n) -&gt; int {
      if (n == 0) return -1;
      if (cache[n]) return cache[n];
      for (int i = sqrt(n); i &gt;= 1; --i)
        if (win(n - i * i) &lt; 0) return cache[n] = 1;      
      return cache[n] = -1;
    };
    return win(n) &gt; 0;
  }
};</pre>

</div><h2 class="tabtitle">Java</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag">class Solution {
  private int[] cache;
  public boolean winnerSquareGame(int n) {
    this.cache = new int[n + 1];
    return this.win(n) &gt; 0;
  }
  
  private int win(int n) {
    if (n == 0) return -1;
    if (this.cache[n] != 0) return this.cache[n];
    for (int i = (int)Math.sqrt(n); i &gt;= 1; --i)
      if (win(n - i * i) &lt; 0) 
        return this.cache[n] = 1;
    return this.cache[n] = -1;
  }
}</pre>

</div><h2 class="tabtitle">Python3</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag">class Solution:
  def winnerSquareGame(self, n: int) -&gt; bool:
    dp = [None] * (n + 1)
    dp[0] = False
    for i in range(0, n):      
      if dp[i]: continue
      for j in range(1, n + 1):      
        if i + j * j &gt; n: break
        dp[i + j * j] = True
    return dp[n]</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/game-theory/leetcode-1510-stone-game-iv/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 1406. Stone Game III</title>
		<link>https://zxi.mytechroad.com/blog/game-theory/leetcode-1406-stone-game-iii/</link>
					<comments>https://zxi.mytechroad.com/blog/game-theory/leetcode-1406-stone-game-iii/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 05 Apr 2020 18:54:55 +0000</pubDate>
				<category><![CDATA[Game Theory]]></category>
		<category><![CDATA[game]]></category>
		<category><![CDATA[minmax]]></category>
		<category><![CDATA[score]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=6587</guid>

					<description><![CDATA[Alice and Bob continue their&#160;games with piles of stones. There are several stones&#160;arranged in a row, and each stone has an associated&#160;value which is an&#8230;]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="花花酱 LeetCode 1406. Stone Game III - 刷题找工作 EP318" width="500" height="375" src="https://www.youtube.com/embed/uzfsrChj8dM?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>Alice and Bob continue their&nbsp;games with piles of stones. There are several stones&nbsp;<strong>arranged in a row</strong>, and each stone has an associated&nbsp;value which is an integer given in the array&nbsp;<code>stoneValue</code>.</p>



<p>Alice and Bob take turns, with&nbsp;<strong>Alice</strong>&nbsp;starting first. On each player&#8217;s turn, that player&nbsp;can take&nbsp;<strong>1, 2 or 3 stones</strong>&nbsp;from&nbsp;the&nbsp;<strong>first</strong>&nbsp;remaining stones in the row.</p>



<p>The score of each player is the sum of values of the stones taken. The score of each player is&nbsp;<strong>0</strong>&nbsp;initially.</p>



<p>The objective of the game is to end with the highest score, and the winner is the player with the highest score and there could be a tie. The game continues until all the stones have been taken.</p>



<p>Assume&nbsp;Alice&nbsp;and Bob&nbsp;<strong>play optimally</strong>.</p>



<p>Return&nbsp;<em>&#8220;Alice&#8221;</em>&nbsp;if&nbsp;Alice will win,&nbsp;<em>&#8220;Bob&#8221;</em>&nbsp;if Bob will win or&nbsp;<em>&#8220;Tie&#8221;</em>&nbsp;if they end the game with the same score.</p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> values = [1,2,3,7]
<strong>Output:</strong> "Bob"
<strong>Explanation:</strong> Alice will always lose. Her best move will be to take three piles and the score become 6. Now the score of Bob is 7 and Bob wins.
</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> values = [1,2,3,-9]
<strong>Output:</strong> "Alice"
<strong>Explanation:</strong> Alice must choose all the three piles at the first move to win and leave Bob with negative score.
If Alice chooses one pile her score will be 1 and the next move Bob's score becomes 5. The next move Alice will take the pile with value = -9 and lose.
If Alice chooses two piles her score will be 3 and the next move Bob's score becomes 3. The next move Alice will take the pile with value = -9 and also lose.
Remember that both play optimally so here Alice will choose the scenario that makes her win.
</pre>



<p><strong>Example 3:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> values = [1,2,3,6]
<strong>Output:</strong> "Tie"
<strong>Explanation:</strong> Alice cannot win this game. She can end the game in a draw if she decided to choose all the first three piles, otherwise she will lose.
</pre>



<p><strong>Example 4:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> values = [1,2,3,-1,-2,-3,7]
<strong>Output:</strong> "Alice"
</pre>



<p><strong>Example 5:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> values = [-1,-2,-3]
<strong>Output:</strong> "Tie"
</pre>



<p><strong>Constraints:</strong></p>



<ul class="wp-block-list"><li><code>1 &lt;= values.length &lt;= 50000</code></li><li><code>-1000&nbsp;&lt;= values[i] &lt;= 1000</code></li></ul>



<h2 class="wp-block-heading"><strong>Solution: DP with memorization</strong></h2>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="960" height="540" src="https://zxi.mytechroad.com/blog/wp-content/uploads/2020/04/1406-ep318.png" alt="" class="wp-image-6592" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2020/04/1406-ep318.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2020/04/1406-ep318-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2020/04/1406-ep318-768x432.png 768w" sizes="auto, (max-width: 960px) 100vw, 960px" /></figure>



<p>dp(i) := max relative score the current player can get if start the game from the i-th stone.</p>



<p>dp(i) = max(sum(values[i:i+k]) &#8211; dp(i + k)) 1 &lt;= k &lt;= 3</p>



<p>Time complexity: O(n)<br>Space complexity: O(n)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class Solution {
public:
  string stoneGameIII(vector&lt;int&gt;&amp; stoneValue) {
    const int n = stoneValue.size();
    vector&lt;int&gt; mem(n, INT_MIN);
    
    // Maximum `relative score` the current player can achieve
    // if start from the i-th stone.
    function&lt;int(int)&gt; dp = [&amp;](int i) {
      if (i &gt;= n) return 0; // end of game.
      if (mem[i] != INT_MIN) return mem[i];      
      for (int j = 0, s = 0; j &lt; 3 &amp;&amp; i + j &lt; n; ++j) {
        s += stoneValue[i + j];
        // s - dp(.) to get `relative score`.
        mem[i] = max(mem[i], s - dp(i + j + 1));
      }      
      return mem[i];
    };
    
    const int score = dp(0);    
    return score &gt; 0 ? &quot;Alice&quot; : (score == 0 ? &quot;Tie&quot; : &quot;Bob&quot;);
  }
};</pre>
</div></div>



<div class="responsive-tabs">
<h2 class="tabtitle">Python3</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag"># Author: Huahua
class Solution:
  def stoneGameIII(self, stoneValue: List[int]) -&gt; str:
    n = len(stoneValue)
    stoneValue += [0, 0, 0]
    dp = [-10**9] * n + [0, 0, 0]
    for i in range(n - 1, -1, -1):
      for k in (1, 2, 3):
        dp[i] = max(dp[i], sum(stoneValue[i:i+k]) - dp[i+k])    
    return &quot;Alice&quot; if dp[0] &gt; 0 else &quot;Bob&quot; if dp[0] &lt; 0 else &quot;Tie&quot;</pre>
</div></div>



<h2 class="wp-block-heading"><strong>Related Problems</strong></h2>



<ul class="wp-block-list"><li><a href="https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-877-stone-game/">https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-877-stone-game/</a></li><li><a href="https://zxi.mytechroad.com/blog/recursion/leetcode-1140-stone-game-ii/">https://zxi.mytechroad.com/blog/recursion/leetcode-1140-stone-game-ii/</a></li><li><a href="https://zxi.mytechroad.com/blog/leetcode/leetcode-486-predict-the-winner/">https://zxi.mytechroad.com/blog/leetcode/leetcode-486-predict-the-winner/</a></li></ul>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/game-theory/leetcode-1406-stone-game-iii/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 375. Guess Number Higher or Lower II</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-375-guess-number-higher-or-lower-ii/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-375-guess-number-higher-or-lower-ii/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sat, 14 Mar 2020 03:22:21 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[game]]></category>
		<category><![CDATA[medium]]></category>
		<category><![CDATA[O(n^3)]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=6465</guid>

					<description><![CDATA[We are playing the Guess Game. The game is as follows: I pick a number from&#160;1&#160;to&#160;n. You have to guess which number I picked. Every&#8230;]]></description>
										<content:encoded><![CDATA[
<p>We are playing the Guess Game. The game is as follows:</p>



<p>I pick a number from&nbsp;<strong>1</strong>&nbsp;to&nbsp;<strong>n</strong>. You have to guess which number I picked.</p>



<p>Every time you guess wrong, I&#8217;ll tell you whether the number I picked is higher or lower.</p>



<p>However, when you guess a particular number x, and you guess wrong, you pay&nbsp;<strong>$x</strong>. You win the game when you guess the number I picked.</p>



<p><strong>Example:</strong></p>



<pre class="wp-block-preformatted;crayon:false">n = 10, I pick 8.

First round:  You guess 5, I tell you that it's higher. You pay $5.
Second round: You guess 7, I tell you that it's higher. You pay $7.
Third round:  You guess 9, I tell you that it's lower. You pay $9.

Game over. 8 is the number I picked.

You end up paying $5 + $7 + $9 = $21.
</pre>



<p>Given a particular&nbsp;<strong>n ≥ 1</strong>, find out how much money you need to have to guarantee a&nbsp;<strong>win</strong>.</p>



<h2 class="wp-block-heading"><strong>Solution: DP</strong></h2>



<p>Use dp[l][r] to denote the min money to win the game if the current guessing range is [l, r], to guarantee a win, we need to try all possible numbers in [l, r]. Let say we guess K, we need to pay K and the game might continue if we were wrong. cost will be K + max(dp(l, K-1), dp(K+1, r)), we need max to cover all possible cases. Among all Ks, we picked the cheapest one.</p>



<p>dp[l][r] = min(k + max(dp[l][k &#8211; 1], dp[k+1][r]), for l &lt;= k &lt;= r.</p>



<p>Time complexity: O(n^3)<br>Space complexity: O(n^2)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class Solution {
public:
  int getMoneyAmount(int n) {
    constexpr int kInf = 1e9;
    vector&lt;vector&lt;int&gt;&gt; cache(n + 2, vector&lt;int&gt;(n + 2, kInf));
    function&lt;int(int, int)&gt; dp = [&amp;](int l, int r) {
      int&amp; ans = cache[l][r];
      if (l &gt;= r) return 0;
      if (ans != kInf) return ans;
      for (int x = l; x &lt;= r; ++x)
        ans = min(ans, x + max(dp(l, x - 1), dp(x + 1, r)));
      return ans;
    };
    return dp(1, n);
  }
};</pre>
</div></div>



<div class="responsive-tabs">
<h2 class="tabtitle">Python3</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag"># Author: Huahua
class Solution:
  def getMoneyAmount(self, n: int) -&gt; int:
    @lru_cache(maxsize=None)
    def dp(l, r):      
      return min([k + max(dp(l, k - 1), dp(k + 1, r)) 
                  for k in range(l, r + 1)]) if l &lt; r else 0
    return dp(1, n)</pre>
</div></div>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-375-guess-number-higher-or-lower-ii/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 1275. Find Winner on a Tic Tac Toe Game</title>
		<link>https://zxi.mytechroad.com/blog/simulation/leetcode-1275-find-winner-on-a-tic-tac-toe-game/</link>
					<comments>https://zxi.mytechroad.com/blog/simulation/leetcode-1275-find-winner-on-a-tic-tac-toe-game/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Mon, 02 Dec 2019 06:51:54 +0000</pubDate>
				<category><![CDATA[Simulation]]></category>
		<category><![CDATA[easy]]></category>
		<category><![CDATA[game]]></category>
		<category><![CDATA[simulation]]></category>
		<category><![CDATA[string]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=5904</guid>

					<description><![CDATA[Tic-tac-toe is played&#160;by&#160;two players&#160;A&#160;and&#160;B&#160;on a&#160;3&#160;x&#160;3&#160;grid. Here are the rules of Tic-Tac-Toe: Players take turns placing characters into empty squares (&#8221; &#8220;). The first player&#160;A&#160;always places&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Tic-tac-toe is played&nbsp;by&nbsp;two players&nbsp;<em>A</em>&nbsp;and&nbsp;<em>B</em>&nbsp;on a&nbsp;<em>3</em>&nbsp;x&nbsp;<em>3</em>&nbsp;grid.</p>



<p>Here are the rules of Tic-Tac-Toe:</p>



<ul class="wp-block-list"><li>Players take turns placing characters into empty squares (&#8221; &#8220;).</li><li>The first player&nbsp;<em>A</em>&nbsp;always places &#8220;X&#8221; characters, while the second player&nbsp;<em>B</em>&nbsp;always places &#8220;O&#8221; characters.</li><li>&#8220;X&#8221; and &#8220;O&#8221; characters are always placed into empty squares, never on filled ones.</li><li>The game ends when there are 3 of the same (non-empty) character filling any row, column, or diagonal.</li><li>The game also ends if all squares are non-empty.</li><li>No more moves can be played if the game is over.</li></ul>



<p>Given an array&nbsp;<code>moves</code>&nbsp;where each element&nbsp;is another array of size 2 corresponding to the row and column of the grid where they mark their respective character in the order in which&nbsp;<em>A</em>&nbsp;and&nbsp;<em>B</em>&nbsp;play.</p>



<p>Return the winner of the game if it exists (<em>A</em>&nbsp;or&nbsp;<em>B</em>), in case the game ends in a draw return &#8220;Draw&#8221;, if there are still movements to play return &#8220;Pending&#8221;.</p>



<p>You can assume that&nbsp;<code>moves</code>&nbsp;is&nbsp;<strong>valid</strong>&nbsp;(It follows the rules of Tic-Tac-Toe),&nbsp;the grid is initially empty and&nbsp;<em>A</em>&nbsp;will play&nbsp;<strong>first</strong>.</p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> moves = [[0,0],[2,0],[1,1],[2,1],[2,2]]
<strong>Output:</strong> "A"
<strong>Explanation:</strong> "A" wins, he always plays first.
"X  "    "X  "    "X  "    "X  "    "<strong>X</strong>  "
"   " -&gt; "   " -&gt; " X " -&gt; " X " -&gt; " <strong>X</strong> "
"   "    "O  "    "O  "    "OO "    "OO<strong>X</strong>"
</pre>



<p><strong>Example 2:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> moves = [[0,0],[1,1],[0,1],[0,2],[1,0],[2,0]]
<strong>Output:</strong> "B"
<strong>Explanation:</strong> "B" wins.
"X  "    "X  "    "XX "    "XXO"    "XXO"    "XX<strong>O</strong>"
"   " -&gt; " O " -&gt; " O " -&gt; " O " -&gt; "XO " -&gt; "X<strong>O</strong> " 
"   "    "   "    "   "    "   "    "   "    "<strong>O</strong>  "
</pre>



<p><strong>Example 3:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> moves = [[0,0],[1,1],[2,0],[1,0],[1,2],[2,1],[0,1],[0,2],[2,2]]
<strong>Output:</strong> "Draw"
<strong>Explanation:</strong> The game ends in a draw since there are no moves to make.
"XXO"
"OOX"
"XOX"
</pre>



<p><strong>Example 4:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> moves = [[0,0],[1,1]]
<strong>Output:</strong> "Pending"
<strong>Explanation:</strong> The game has not finished yet.
"X  "
" O "
"   "
</pre>



<p><strong>Constraints:</strong></p>



<ul class="wp-block-list"><li><code>1 &lt;= moves.length &lt;= 9</code></li><li><code>moves[i].length == 2</code></li><li><code>0 &lt;= moves[i][j] &lt;= 2</code></li><li>There are no repeated elements on&nbsp;<code>moves</code>.</li><li><code>moves</code>&nbsp;follow the rules of tic tac toe.</li></ul>



<h2 class="wp-block-heading"><strong>Solution: Simulation</strong></h2>



<p>Time complexity: O(1)<br>Space complexity: O(1)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
class Solution {
public:
  string tictactoe(vector&lt;vector&lt;int&gt;&gt;&amp; moves) {
    vector&lt;vector&lt;string&gt;&gt; b(3, vector&lt;string&gt;(3, &quot;#&quot;));
    bool A = true;
    for (const auto&amp; move : moves) {
      b[move[0]][move[1]] = A ? &quot;A&quot; : &quot;B&quot;;
      A = !A;
    }
    for (int i = 0; i &lt; 3; ++i) {
      if (b[i][0] == b[i][1] &amp;&amp; b[i][2] == b[i][1] &amp;&amp; b[i][0] != &quot;#&quot;)
        return b[i][0];
      if (b[0][i] == b[1][i] &amp;&amp; b[2][i] == b[1][i] &amp;&amp; b[0][i] != &quot;#&quot;)
        return b[0][i];
    }
    if (b[0][0] == b[1][1] &amp;&amp; b[1][1] == b[2][2] &amp;&amp; b[1][1] != &quot;#&quot;)
      return b[1][1];
    if (b[2][0] == b[1][1] &amp;&amp; b[1][1] == b[0][2] &amp;&amp; b[1][1] != &quot;#&quot;)
      return b[1][1];
    return moves.size() == 9 ? &quot;Draw&quot; : &quot;Pending&quot;;
  }
};</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/simulation/leetcode-1275-find-winner-on-a-tic-tac-toe-game/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 1140. Stone Game II</title>
		<link>https://zxi.mytechroad.com/blog/recursion/leetcode-1140-stone-game-ii/</link>
					<comments>https://zxi.mytechroad.com/blog/recursion/leetcode-1140-stone-game-ii/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 28 Jul 2019 05:47:25 +0000</pubDate>
				<category><![CDATA[Recursion]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[game]]></category>
		<category><![CDATA[medium]]></category>
		<category><![CDATA[recursion]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=5368</guid>

					<description><![CDATA[Alex&#160;and Lee continue their&#160;games with piles of stones.&#160; There are a number of&#160;piles&#160;arranged in a row, and each pile has a positive integer number of&#8230;]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="花花酱 LeetCode 1140. Stone Game II - 刷题找工作 EP260" width="500" height="375" src="https://www.youtube.com/embed/e_FrC5xavwI?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>Alex&nbsp;and Lee continue their&nbsp;games with piles of stones.&nbsp; There are a number of&nbsp;piles&nbsp;<strong>arranged in a row</strong>, and each pile has a positive integer number of stones&nbsp;<code>piles[i]</code>.&nbsp; The objective of the game is to end with the most&nbsp;stones.&nbsp;</p>



<p>Alex and Lee take turns, with Alex starting first.&nbsp; Initially,&nbsp;<code>M = 1</code>.</p>



<p>On each player&#8217;s turn, that player&nbsp;can take&nbsp;<strong>all the stones</strong>&nbsp;in the&nbsp;<strong>first</strong>&nbsp;<code>X</code>&nbsp;remaining piles, where&nbsp;<code>1 &lt;= X &lt;= 2M</code>.&nbsp; Then, we set&nbsp;<code>M = max(M, X)</code>.</p>



<p>The game continues until all the stones have been taken.</p>



<p>Assuming Alex and Lee play optimally, return the maximum number of stones Alex can get.</p>



<p><strong>Example 1:</strong></p>



<pre class="wp-block-preformatted; crayon:false"><strong>Input:</strong> piles = [2,7,9,4,4]
<strong>Output:</strong> 10
<strong>Explanation:</strong>  If Alex takes one pile at the beginning, Lee takes two piles, then Alex takes 2 piles again. Alex can get 2 + 4 + 4 = 10 piles in total. If Alex takes two piles at the beginning, then Lee can take all three piles left. In this case, Alex get 2 + 7 = 9 piles in total. So we return 10 since it's larger. 
</pre>



<p><strong>Constraints:</strong></p>



<ul class="wp-block-list"><li><code>1 &lt;= piles.length &lt;= 100</code></li><li><code>1 &lt;= piles[i]&nbsp;&lt;= 10 ^ 4</code></li></ul>



<h2 class="wp-block-heading"><strong>Solution: Recursion + Memoization</strong></h2>



<p>def solve(s, m) = max diff score between two players starting from s for the given M.</p>



<p>cache[s][M] = max{sum(piles[s:s+x]) &#8211; solve(s+x, max(x, M)}, 1 &lt;= x &lt;= 2*M, s + x &lt;= n</p>



<p>Time complexity: O(n^3)<br>Space complexity: O(n^2)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua, 12 ms / 9.7 MB
class Solution {
public:
  int stoneGameII(vector&lt;int&gt;&amp; piles) {
    const int n = piles.size();
    unordered_map&lt;int, int&gt; cache;
    // Maximum diff starting from piles[s] given M.
    function&lt;int(int, int)&gt; solve = [&amp;](int s, int M) {
      if (s &gt;= n) return 0;
      const int key = (s &lt;&lt; 8) | M;
      if (cache.count(key)) return cache[key];
      int best = INT_MIN;
      int curr = 0;
      for (int x = 1; x &lt;= 2 * M; ++x) {
        if (s + x &gt; n) break;
        curr += piles[s + x - 1];
        best = max(best, curr - solve(s + x, max(x, M)));
      }
      return cache[key] = best;
    };    
    int total = accumulate(begin(piles), end(piles), 0);
    return  (total + solve(0, 1)) / 2;
  }
};</pre>
</div></div>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/recursion/leetcode-1140-stone-game-ii/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 45. Jump Game II</title>
		<link>https://zxi.mytechroad.com/blog/greedy/leetcode-45-jump-game-ii/</link>
					<comments>https://zxi.mytechroad.com/blog/greedy/leetcode-45-jump-game-ii/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 28 Apr 2019 18:44:27 +0000</pubDate>
				<category><![CDATA[Greedy]]></category>
		<category><![CDATA[game]]></category>
		<category><![CDATA[greedy]]></category>
		<category><![CDATA[jump]]></category>
		<guid isPermaLink="false">https://zxi.mytechroad.com/blog/?p=5118</guid>

					<description><![CDATA[Given an array of non-negative integers, you are initially positioned at the first index of the array. Each element in the array represents your maximum&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Given an array of non-negative integers, you are initially positioned at the first index of the array.</p>



<p>Each element in the array represents your maximum jump length at that position.</p>



<p>Your goal is to reach the last index in the minimum number of jumps.</p>



<p><strong>Example:</strong></p>



<pre class="wp-block-preformatted;crayon:false"><strong>Input:</strong> [2,3,1,1,4]
<strong>Output:</strong> 2
<strong>Explanation:</strong> The minimum number of jumps to reach the last index is 2.
    Jump 1 step from index 0 to 1, then 3 steps to the last index.</pre>



<p><strong>Note:</strong></p>



<p>You can assume that you can always reach the last index.</p>



<h2 class="wp-block-heading"><strong>Solution: Greedy</strong></h2>



<p>Jump as far as possible but lazily. </p>



<pre class="wp-block-preformatted;crayon:false">
[2, 3, 1, 1, 4]
i    nums[i]   steps   near   far
-      -         0       0     0
0      2         0       0     2
1      3         1       2     4
2      1         1       2     4
3      1         2       4     4
4      4         2       4     8
</pre>



<p>Time complexity: O(n)<br>Space complexity: O(1)</p>



<div class="responsive-tabs">
<h2 class="tabtitle">C++</h2>
<div class="tabcontent">

<pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua, running time: 12 ms / 10.3 MB
class Solution {
public:
  int jump(vector&lt;int&gt;&amp; nums) {
    int steps = 0;
    int near = 0;
    int far = 0;
    for (int i = 0; i &lt; nums.size(); ++i) {
      if (i &gt; near) {
        ++steps;
        near = far;
      }
      far = max(far, i + nums[i]);      
    }
    return steps;
  }
};</pre>
</div></div>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/greedy/leetcode-45-jump-game-ii/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 877. Stone Game</title>
		<link>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-877-stone-game/</link>
					<comments>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-877-stone-game/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 29 Jul 2018 04:53:23 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[dp]]></category>
		<category><![CDATA[game]]></category>
		<category><![CDATA[min-max]]></category>
		<guid isPermaLink="false">http://zxi.mytechroad.com/blog/?p=3354</guid>

					<description><![CDATA[Problem Alex and Lee play a game with piles of stones.  There are an even number of piles arranged in a row, and each pile has a&#8230;]]></description>
										<content:encoded><![CDATA[<p><iframe loading="lazy" title="花花酱 LeetCode 877 Stone Game - 刷题找工作 EP213" width="500" height="375" src="https://www.youtube.com/embed/xJ1Rc30Pyes?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<h1><strong>Problem</strong></h1>
<p>Alex and Lee play a game with piles of stones.  There are an even number of piles <strong>arranged in a row</strong>, and each pile has a positive integer number of stones <code>piles[i]</code>.</p>
<p>The objective of the game is to end with the most stones.  The total number of stones is odd, so there are no ties.</p>
<p>Alex and Lee take turns, with Alex starting first.  Each turn, a player takes the entire pile of stones from either the beginning or the end of the row.  This continues until there are no more piles left, at which point the person with the most stones wins.</p>
<p>Assuming Alex and Lee play optimally, return <code>True</code> if and only if Alex wins the game.</p>
<p><strong>Example 1:</strong></p>
<pre class="crayon:false"><strong>Input: </strong><span id="example-input-1-1">[5,3,4,5]</span>
<strong>Output: </strong><span id="example-output-1">true</span>
<strong>Explanation: </strong>
Alex starts first, and can only take the first 5 or the last 5.
Say he takes the first 5, so that the row becomes [3, 4, 5].
If Lee takes 3, then the board is [4, 5], and Alex takes 5 to win with 10 points.
If Lee takes the last 5, then the board is [3, 4], and Alex takes 4 to win with 9 points.
This demonstrated that taking the first 5 was a winning move for Alex, so we return true.
</pre>
<p><strong>Note:</strong></p>
<ol>
<li><code>2 &lt;= piles.length &lt;= 500</code></li>
<li><code>piles.length</code> is even.</li>
<li><code>1 &lt;= piles[i] &lt;= 500</code></li>
<li><code>sum(piles)</code> is odd.</li>
</ol>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-3385" src="http://zxi.mytechroad.com/blog/wp-content/uploads/2018/07/877-ep213.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2018/07/877-ep213.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/07/877-ep213-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2018/07/877-ep213-768x432.png 768w" sizes="auto, (max-width: 960px) 100vw, 960px" /></p>
<h1><strong>Solution 1: min-max (TLE)</strong></h1>
<p>Time complexity: O(2^n)</p>
<p>Space complexity: O(n)</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: TLE 26/46 passed.
class Solution {
public:
  bool stoneGame(vector&lt;int&gt;&amp; piles) {
    return score(piles, 0, piles.size() - 1) &gt; 0;
  }
private:
  int score(const vector&lt;int&gt;&amp; piles, int l, int r) {
    if (l == r) return piles[l];
    return max(piles[l] - score(piles, l + 1, r),
               piles[r] - score(piles, l, r - 1));
  }
};</pre><p></p>
<h1><strong>Solution 2: min-max + memorization</strong></h1>
<p>Time complexity: O(n^2)</p>
<p>Space complexity: O(n^2)</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: 12 ms
class Solution {
public:
  bool stoneGame(vector&lt;int&gt;&amp; piles) {
    const int n = piles.size();
    m_ = vector&lt;vector&lt;int&gt;&gt;(n, vector&lt;int&gt;(n, INT_MIN));
    return score(piles, 0, n - 1) &gt; 0;
  }
private:
  vector&lt;vector&lt;int&gt;&gt; m_;
  int score(const vector&lt;int&gt;&amp; piles, int l, int r) {
    if (l == r) return piles[l];
    if (m_[l][r] == INT_MIN)
      m_[l][r] = max(piles[l] - score(piles, l + 1, r),
                     piles[r] - score(piles, l, r - 1));
    return m_[l][r];
  }
};</pre><p></p>
<h1><strong>Solution 3:  min-max + DP</strong></h1>
<p>Time complexity: O(n^2)</p>
<p>Space complexity: O(n^2)</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: 8 ms
class Solution {
public:
  bool stoneGame(vector&lt;int&gt;&amp; piles) {
    const int n = piles.size();
    // dp[i][j] := max(your_stones - op_stones) for piles[i] ~ piles[j]
    vector&lt;vector&lt;int&gt;&gt; dp(n, vector&lt;int&gt;(n, 0));
    for (int i = 0; i &lt; n; ++i)
      dp[i][i] = piles[i];
    for (int l = 2; l &lt;= n; ++l)
      for (int i = 0; i &lt; n - l + 1; ++i) {
        int j = i + l - 1;
        dp[i][j] = max(piles[i] - dp[i + 1][j], piles[j] - dp[i][j - 1]);
      }
    return dp[0][n - 1] &gt; 0;    
  }
};</pre><p>O(n) Space</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: 4 ms
class Solution {
public:
  bool stoneGame(vector&lt;int&gt;&amp; piles) {
    const int n = piles.size();
    // dp[i] := max(your_stones - op_stones) for piles[i] to piles[i + l - 1]
    vector&lt;int&gt; dp(piles);    
    for (int l = 2; l &lt;= n; ++l)
      for (int i = 0; i &lt; n - l + 1; ++i)       
        dp[i] = max(piles[i] - dp[i + 1], piles[i + l - 1] - dp[i]);
    return dp[0] &gt; 0;
  }
};</pre><p></p>
<h1><strong>Related Problems</strong></h1>
<ul>
<li><a href="http://zxi.mytechroad.com/blog/leetcode/leetcode-486-predict-the-winner/">花花酱 LeetCode 486. Predict the Winner</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-877-stone-game/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 794. Valid Tic-Tac-Toe State</title>
		<link>https://zxi.mytechroad.com/blog/string/leetcode-794-valid-tic-tac-toe-state/</link>
					<comments>https://zxi.mytechroad.com/blog/string/leetcode-794-valid-tic-tac-toe-state/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sun, 04 Mar 2018 05:08:04 +0000</pubDate>
				<category><![CDATA[Simulation]]></category>
		<category><![CDATA[String]]></category>
		<category><![CDATA[game]]></category>
		<category><![CDATA[medium]]></category>
		<category><![CDATA[string]]></category>
		<guid isPermaLink="false">http://zxi.mytechroad.com/blog/?p=1930</guid>

					<description><![CDATA[题目大意：判断一个井字棋的棋盘是否有效。 A Tic-Tac-Toe board is given as a string array board. Return True if and only if it is possible to reach this board position during&#8230;]]></description>
										<content:encoded><![CDATA[<p>题目大意：判断一个井字棋的棋盘是否有效。</p>
<p>A Tic-Tac-Toe board is given as a string array <code>board</code>. Return True if and only if it is possible to reach this board position during the course of a valid tic-tac-toe game.</p>
<p>The <code>board</code> is a 3 x 3 array, and consists of characters <code>" "</code>, <code>"X"</code>, and <code>"O"</code>.  The &#8221; &#8221; character represents an empty square.</p>
<p>Here are the rules of Tic-Tac-Toe:</p>
<ul>
<li>Players take turns placing characters into empty squares (&#8221; &#8220;).</li>
<li>The first player always places &#8220;X&#8221; characters, while the second player always places &#8220;O&#8221; characters.</li>
<li>&#8220;X&#8221; and &#8220;O&#8221; characters are always placed into empty squares, never filled ones.</li>
<li>The game ends when there are 3 of the same (non-empty) character filling any row, column, or diagonal.</li>
<li>The game also ends if all squares are non-empty.</li>
<li>No more moves can be played if the game is over.</li>
</ul>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">Example 1:
Input: board = [&quot;O&nbsp; &quot;, &quot;&nbsp; &nbsp;&quot;, &quot;&nbsp; &nbsp;&quot;]
Output: false
Explanation: The first player always plays &quot;X&quot;.

Example 2:
Input: board = [&quot;XOX&quot;, &quot; X &quot;, &quot;   &quot;]
Output: false
Explanation: Players take turns making moves.

Example 3:
Input: board = [&quot;XXX&quot;, &quot;   &quot;, &quot;OOO&quot;]
Output: false

Example 4:
Input: board = [&quot;XOX&quot;, &quot;O O&quot;, &quot;XOX&quot;]
Output: true</pre><p><strong>Note:</strong></p>
<ul>
<li><code>board</code> is a length-3 array of strings, where each string <code>board[i]</code> has length 3.</li>
<li>Each <code>board[i][j]</code> is a character in the set <code>{" ", "X", "O"}</code>.</li>
</ul>
<p><b>Idea: Verify all rules</b></p>
<p>C++</p><pre class="urvanov-syntax-highlighter-plain-tag">class Solution {
public:  
  bool validTicTacToe(vector&lt;string&gt;&amp; board) {    
    int x = 0;
    int o = 0;
    int wins_x = getWins(board, 'X', x);
    int wins_o = getWins(board, 'O', o);    
    return wins_x + wins_o &lt;= 1 &amp;&amp; x &gt;= o + wins_x &amp;&amp; x &lt;= o + 1 - wins_o;
  }
private:
  int getWins(const vector&lt;string&gt;&amp; board, char p, int&amp; count) {
    vector&lt;string&gt; rows(3);
    string diag1, diag2;
    for (int i = 0; i &lt; 3; ++i) {
      diag1 += board[i][i];
      diag2 += board[i][2 - i];
      for (int j = 0; j &lt; 3; ++j) {
        char c = board[i][j];
        rows[j] += c;
        count += c == p;
      }
    }    
    string win(3, p);
    int wins = (diag1 == win) + (diag2 == win);
    for (int i = 0; i &lt; 3; ++i) {
      wins += rows[i] == win;
      wins += board[i] == win;
    }
    return wins;
  }
};</pre><p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/string/leetcode-794-valid-tic-tac-toe-state/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>花花酱 LeetCode 486. Predict the Winner</title>
		<link>https://zxi.mytechroad.com/blog/leetcode/leetcode-486-predict-the-winner/</link>
					<comments>https://zxi.mytechroad.com/blog/leetcode/leetcode-486-predict-the-winner/#respond</comments>
		
		<dc:creator><![CDATA[zxi]]></dc:creator>
		<pubDate>Sat, 25 Mar 2017 05:38:38 +0000</pubDate>
				<category><![CDATA[Dynamic Programming]]></category>
		<category><![CDATA[Leetcode]]></category>
		<category><![CDATA[dynamic programming]]></category>
		<category><![CDATA[game]]></category>
		<category><![CDATA[medium]]></category>
		<category><![CDATA[min-max]]></category>
		<category><![CDATA[recursion]]></category>
		<guid isPermaLink="false">http://zxi.mytechroad.com/blog/?p=37</guid>

					<description><![CDATA[Problem Given an array of scores that are non-negative integers. Player 1 picks one of the numbers from either end of the array followed by&#8230;]]></description>
										<content:encoded><![CDATA[<p><iframe loading="lazy" title="花花酱 LeetCode 486. Predict the Winner - 刷题找工作 EP185" width="500" height="375" src="https://www.youtube.com/embed/g5wLHFTodm0?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<h1><strong>Problem</strong></h1>
<p>Given an array of scores that are non-negative integers. Player 1 picks one of the numbers from either end of the array followed by the player 2 and then player 1 and so on. Each time a player picks a number, that number will not be available for the next player. This continues until all the scores have been chosen. The player with the maximum score wins.</p>
<p>Given an array of scores, predict whether player 1 is the winner. You can assume each player plays to maximize his score.</p>
<p><strong>Example 1:</strong><br />
Input: [1, 5, 2]<br />
Output: False<br />
Explanation: Initially, player 1 can choose between 1 and 2.<br />
If he chooses 2 (or 1), then player 2 can choose from 1 (or 2) and 5. If player 2 chooses 5, then player 1 will be left with 1 (or 2).<br />
So, final score of player 1 is 1 + 2 = 3, and player 2 is 5.<br />
Hence, player 1 will never be the winner and you need to return False.</p>
<p><strong>Example 2:</strong><br />
Input: [1, 5, 233, 7]<br />
Output: True<br />
Explanation: Player 1 first chooses 1. Then player 2 have to choose between 5 and 7. No matter which number player 2 choose, player 1 can choose 233.<br />
Finally, player 1 has more score (234) than player 2 (12), so you need to return True representing player1 can win.<br />
Note:<br />
1 &lt;= length of the array &lt;= 20.<br />
Any scores in the given array are non-negative integers and will not exceed 10,000,000.<br />
If the scores of both players are equal, then player 1 is still the winner.</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2768" src="http://zxi.mytechroad.com/blog/wp-content/uploads/2017/03/486-ep185.png" alt="" width="960" height="540" srcset="https://zxi.mytechroad.com/blog/wp-content/uploads/2017/03/486-ep185.png 960w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/03/486-ep185-300x169.png 300w, https://zxi.mytechroad.com/blog/wp-content/uploads/2017/03/486-ep185-768x432.png 768w" sizes="auto, (max-width: 960px) 100vw, 960px" /></p>
<h1><strong>Solution 1: Recursion</strong></h1>
<p>Time complexity: O(2^n)</p>
<p>Space complexity: O(n)</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: 67 ms
class Solution {
public:
  bool PredictTheWinner(vector&lt;int&gt;&amp; nums) {    
    return getScore(nums, 0, nums.size() - 1) &gt;= 0;
  }
private:  
  // Max diff (my_score - op_score) of subarray nums[l] ~ nums[r].
  int getScore(vector&lt;int&gt;&amp; nums, int l, int r) {
    if (l == r) return nums[l];
    return max(nums[l] - getScore(nums, l + 1, r), 
               nums[r] - getScore(nums, l, r - 1));    
  }
};</pre><p></p>
<h1><strong>Solution 2: Recursion + Memoization</strong></h1>
<p>Time complexity: O(n^2)</p>
<p>Space complexity: O(n)</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: 4 ms
class Solution {
public:
  bool PredictTheWinner(vector&lt;int&gt;&amp; nums) {
    m_ = vector&lt;vector&lt;int&gt;&gt;(nums.size(), vector&lt;int&gt;(nums.size(), INT_MIN));
    return getScore(nums, 0, nums.size() - 1) &gt;= 0;
  }
private:
  vector&lt;vector&lt;int&gt;&gt; m_;
  // Max diff (my_score - op_score) of subarray nums[l] ~ nums[r].
  int getScore(vector&lt;int&gt;&amp; nums, int l, int r) {
    if (l == r) return nums[l];    
    if (m_[l][r] != INT_MIN) return m_[l][r];
    m_[l][r] = max(nums[l] - getScore(nums, l + 1, r), 
                   nums[r] - getScore(nums, l, r - 1));
    return m_[l][r];
  }    
};</pre><p>DP version</p><pre class="urvanov-syntax-highlighter-plain-tag">// Author: Huahua
// Running time: 4 ms
class Solution {
public:
  bool PredictTheWinner(vector&lt;int&gt;&amp; nums) {
    const int n = nums.size();
    vector&lt;vector&lt;int&gt;&gt; dp(n, vector&lt;int&gt;(n, INT_MIN));
    for (int i = 0; i &lt; n; ++i)
      dp[i][i] = nums[i];
    for (int l = 2; l &lt;= n; ++l)
      for (int i = 0; i &lt;= n - l; ++i) {
        int j = i + l - 1;
        dp[i][j] = max(nums[i] - dp[i + 1][j], nums[j] - dp[i][j - 1]);
      }
    return dp[0][n - 1] &gt;= 0;
  }
};</pre><p></p>
<h1><strong>Related Problem</strong></h1>
<ul>
<li><a href="https://zxi.mytechroad.com/blog/dynamic-programming/leetcode-877-stone-game/">花花酱 LeetCode 877. Stone Game</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://zxi.mytechroad.com/blog/leetcode/leetcode-486-predict-the-winner/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
