Skip to content

Commit d24b93c

Browse files
committed
deploy: 92f0c5b
1 parent 3e8f8e2 commit d24b93c

File tree

4 files changed

+40
-16
lines changed

4 files changed

+40
-16
lines changed

cpp_tricks/index.html

+19-7
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@
292292
<ul class="nav flex-column">
293293
</ul>
294294
</li>
295-
<li class="nav-item" data-bs-level="2"><a href="#vector_2" class="nav-link">保持有序的 vector</a>
295+
<li class="nav-item" data-bs-level="2"><a href="#vector_2" class="nav-link">保持有序的 vector 用于二分法</a>
296296
<ul class="nav flex-column">
297297
</ul>
298298
</li>
@@ -435,7 +435,7 @@ <h1 id="c">应知应会 C++ 小技巧</h1>
435435
<li><a href="#map">一边遍历 map,一边删除?</a></li>
436436
<li><a href="#vector">高效删除单个 vector 元素</a></li>
437437
<li><a href="#vector_1">批量删除部分 vector 元素</a></li>
438-
<li><a href="#vector_2">保持有序的 vector</a></li>
438+
<li><a href="#vector_2">保持有序的 vector 用于二分法</a></li>
439439
<li><a href="#c_1">C++ 随机数的正确生成方式</a></li>
440440
<li><a href="#const">const 居然应该后置&hellip;</a></li>
441441
<li><a href="#auto">函数参数也可以 auto</a></li>
@@ -870,7 +870,7 @@ <h2 id="vector_1">批量删除部分 vector 元素</h2>
870870
return x &gt; 0; // 删除所有值大于 0 的元素
871871
});
872872
</code></pre>
873-
<h2 id="vector_2">保持有序的 vector</h2>
873+
<h2 id="vector_2">保持有序的 vector 用于二分法</h2>
874874
<p>如果你想要维护一个有序的数组,用 <code>lower_bound</code><code>upper_bound</code> 来插入元素,保证插入后仍保持有序:</p>
875875
<pre><code class="language-cpp">vector&lt;int&gt; s;
876876
s.push_back(1);
@@ -894,27 +894,39 @@ <h2 id="vector_2">保持有序的 vector</h2>
894894
lower_bound(s.begin(), s.end(), 5); // s.begin() + 3;
895895
</code></pre>
896896
<p>有序 vector 应用案例:利用 CDF 积分 + 二分法可以实现生成任意指定分布的随机数。</p>
897-
<p>例如抽卡概率要求</p>
897+
<p>例如数值策划要求的抽卡概率分布是</p>
898898
<ul>
899899
<li>2% 出金卡</li>
900900
<li>10% 出蓝卡</li>
901901
<li>80% 出白卡</li>
902902
<li>8% 出答辩</li>
903903
</ul>
904+
<p>那么你转换一下任务。变成随机生成一个 0 到 1 的浮点数,然后判断:</p>
905+
<ul>
906+
<li>小于 0.02 时,出金卡</li>
907+
<li>小于 0.12 时,出蓝卡</li>
908+
<li>小于 0.92 时,出白卡</li>
909+
<li>小于 1.00 时,出答辩</li>
910+
</ul>
911+
<p>这个转换过程就是 CDF 积分。如果你把这 4 个数按照顺序排列,就是一个有序 vector。</p>
912+
<p>标准库提供了 <code>std::partial_sum</code>(不精准)或 <code>std::inclusive_scan</code>(更精准,C++17 引入)都可以计算一个数组的 CDF 离散积分。</p>
904913
<pre><code class="language-cpp">vector&lt;double&gt; probs = {0.02, 0.1, 0.8, 0.08};
905914
vector&lt;double&gt; cdf;
906915
// 计算 probs 的 CDF 积分,存入 cdf 数组
907-
std::partial_sum(probs.begin(), probs.end(), std::back_inserter(cdf));
908-
// cdf = {0.02, 0.12, 0.92, 1.00} 是一个有序 vector,可以运用二分法
916+
std::inclusive_scan(probs.begin(), probs.end(), std::back_inserter(cdf));
917+
// cdf = {0.02, 0.12, 0.92, 1.00} 是一个有序 vector,可以运用二分法定位
909918

910919
vector&lt;string&gt; result = {&quot;金卡&quot;, &quot;蓝卡&quot;, &quot;白卡&quot;, &quot;答辩&quot;};
911920
// 生成 100 个随机数:
912921
for (int i = 0; i &lt; 100; ++i) {
913-
double r = rand() / (RAND_MAX + 1.);
922+
double r = rand() / (RAND_MAX + 1.0);
914923
int index = lower_bound(cdf.begin(), cdf.end(), r) - cdf.begin();
915924
cout &lt;&lt; &quot;你抽到了&quot; &lt;&lt; result[index] &lt;&lt; endl;
916925
}
917926
</code></pre>
927+
<blockquote>
928+
<p><img src="../img/question.png" height="30px" width="auto" style="margin: 0; border: none"/> 顺便一提,CDF 积分的逆运算是离散微分:<code>std::adjacent_difference</code>,可以从 <code>cdf</code> 数组复原出 <code>probs</code> 数组。</p>
929+
</blockquote>
918930
<h2 id="c_1">C++ 随机数的正确生成方式</h2>
919931
<pre><code class="language-cpp">// 错误的写法:
920932
int r = rand() % 10; // 这样写是错误的!

index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ <h2 id="_1">前言</h2>
276276
<blockquote>
277277
<p><img src="./img/bulb.png" height="30px" width="auto" style="margin: 0; border: none"/> 本书还在持续更新中……要追番的话,可以在 <a href="https://github.com/parallel101/cppguidebook">GitHub</a> 点一下右上角的 “Watch” 按钮,每当小彭老师提交新 commit,GitHub 会向你发送一封电子邮件,提醒你小彭老师更新了。</p>
278278
</blockquote>
279-
<p>更新时间:2024年08月28日 22:32:41 (UTC+08:00)</p>
279+
<p>更新时间:2024年08月28日 22:39:05 (UTC+08:00)</p>
280280
<p><a href="https://parallel101.github.io/cppguidebook">在 GitHub Pages 浏览本书</a> | <a href="https://142857.red/book">在小彭老师自己维护的镜像上浏览本书</a></p>
281281
<h2 id="_2">格式约定</h2>
282282
<blockquote>

print_page/index.html

+19-7
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ <h2 id="index-_1">前言</h2>
389389
<blockquote>
390390
<p><img src="../img/bulb.png" height="30px" width="auto" style="margin: 0; border: none"/> 本书还在持续更新中……要追番的话,可以在 <a href="https://github.com/parallel101/cppguidebook">GitHub</a> 点一下右上角的 “Watch” 按钮,每当小彭老师提交新 commit,GitHub 会向你发送一封电子邮件,提醒你小彭老师更新了。</p>
391391
</blockquote>
392-
<p>更新时间:2024年08月28日 22:32:41 (UTC+08:00)</p>
392+
<p>更新时间:2024年08月28日 22:39:05 (UTC+08:00)</p>
393393
<p><a href="https://parallel101.github.io/cppguidebook">在 GitHub Pages 浏览本书</a> | <a href="https://142857.red/book">在小彭老师自己维护的镜像上浏览本书</a></p>
394394
<h2 id="index-_2">格式约定</h2>
395395
<blockquote>
@@ -1066,7 +1066,7 @@ <h2 id="symbols-linkage">符号的链接类型 (linkage)</h2>
10661066
<li><a href="#cpp_tricks-map">一边遍历 map,一边删除?</a></li>
10671067
<li><a href="#cpp_tricks-vector">高效删除单个 vector 元素</a></li>
10681068
<li><a href="#cpp_tricks-vector_1">批量删除部分 vector 元素</a></li>
1069-
<li><a href="#cpp_tricks-vector_2">保持有序的 vector</a></li>
1069+
<li><a href="#cpp_tricks-vector_2">保持有序的 vector 用于二分法</a></li>
10701070
<li><a href="#cpp_tricks-c_1">C++ 随机数的正确生成方式</a></li>
10711071
<li><a href="#cpp_tricks-const">const 居然应该后置&hellip;</a></li>
10721072
<li><a href="#cpp_tricks-auto">函数参数也可以 auto</a></li>
@@ -1501,7 +1501,7 @@ <h2 id="cpp_tricks-vector_1">批量删除部分 vector 元素</h2>
15011501
return x &gt; 0; // 删除所有值大于 0 的元素
15021502
});
15031503
</code></pre>
1504-
<h2 id="cpp_tricks-vector_2">保持有序的 vector</h2>
1504+
<h2 id="cpp_tricks-vector_2">保持有序的 vector 用于二分法</h2>
15051505
<p>如果你想要维护一个有序的数组,用 <code>lower_bound</code> 或 <code>upper_bound</code> 来插入元素,保证插入后仍保持有序:</p>
15061506
<pre><code class="language-cpp">vector&lt;int&gt; s;
15071507
s.push_back(1);
@@ -1525,27 +1525,39 @@ <h2 id="cpp_tricks-vector_2">保持有序的 vector</h2>
15251525
lower_bound(s.begin(), s.end(), 5); // s.begin() + 3;
15261526
</code></pre>
15271527
<p>有序 vector 应用案例:利用 CDF 积分 + 二分法可以实现生成任意指定分布的随机数。</p>
1528-
<p>例如抽卡概率要求:</p>
1528+
<p>例如数值策划要求的抽卡概率分布是:</p>
15291529
<ul>
15301530
<li>2% 出金卡</li>
15311531
<li>10% 出蓝卡</li>
15321532
<li>80% 出白卡</li>
15331533
<li>8% 出答辩</li>
15341534
</ul>
1535+
<p>那么你转换一下任务。变成随机生成一个 0 到 1 的浮点数,然后判断:</p>
1536+
<ul>
1537+
<li>小于 0.02 时,出金卡</li>
1538+
<li>小于 0.12 时,出蓝卡</li>
1539+
<li>小于 0.92 时,出白卡</li>
1540+
<li>小于 1.00 时,出答辩</li>
1541+
</ul>
1542+
<p>这个转换过程就是 CDF 积分。如果你把这 4 个数按照顺序排列,就是一个有序 vector。</p>
1543+
<p>标准库提供了 <code>std::partial_sum</code>(不精准)或 <code>std::inclusive_scan</code>(更精准,C++17 引入)都可以计算一个数组的 CDF 离散积分。</p>
15351544
<pre><code class="language-cpp">vector&lt;double&gt; probs = {0.02, 0.1, 0.8, 0.08};
15361545
vector&lt;double&gt; cdf;
15371546
// 计算 probs 的 CDF 积分,存入 cdf 数组
1538-
std::partial_sum(probs.begin(), probs.end(), std::back_inserter(cdf));
1539-
// cdf = {0.02, 0.12, 0.92, 1.00} 是一个有序 vector,可以运用二分法
1547+
std::inclusive_scan(probs.begin(), probs.end(), std::back_inserter(cdf));
1548+
// cdf = {0.02, 0.12, 0.92, 1.00} 是一个有序 vector,可以运用二分法定位
15401549

15411550
vector&lt;string&gt; result = {&quot;金卡&quot;, &quot;蓝卡&quot;, &quot;白卡&quot;, &quot;答辩&quot;};
15421551
// 生成 100 个随机数:
15431552
for (int i = 0; i &lt; 100; ++i) {
1544-
double r = rand() / (RAND_MAX + 1.);
1553+
double r = rand() / (RAND_MAX + 1.0);
15451554
int index = lower_bound(cdf.begin(), cdf.end(), r) - cdf.begin();
15461555
cout &lt;&lt; &quot;你抽到了&quot; &lt;&lt; result[index] &lt;&lt; endl;
15471556
}
15481557
</code></pre>
1558+
<blockquote>
1559+
<p><img src="../img/question.png" height="30px" width="auto" style="margin: 0; border: none"/> 顺便一提,CDF 积分的逆运算是离散微分:<code>std::adjacent_difference</code>,可以从 <code>cdf</code> 数组复原出 <code>probs</code> 数组。</p>
1560+
</blockquote>
15491561
<h2 id="cpp_tricks-c_1">C++ 随机数的正确生成方式</h2>
15501562
<pre><code class="language-cpp">// 错误的写法:
15511563
int r = rand() % 10; // 这样写是错误的!

search/search_index.json

+1-1
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)