-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
495 lines (293 loc) · 663 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>DepletedPrism's Blog</title>
<subtitle>厌离秽土, 欣求净土.</subtitle>
<link href="https://depletedprism.github.io/atom.xml" rel="self"/>
<link href="https://depletedprism.github.io/"/>
<updated>2024-12-16T05:34:17.302Z</updated>
<id>https://depletedprism.github.io/</id>
<author>
<name>DepletedPrism</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>「置顶」算法教程合辑</title>
<link href="https://depletedprism.github.io/compilation/"/>
<id>https://depletedprism.github.io/compilation/</id>
<published>9102-11-14T00:11:23.000Z</published>
<updated>2024-12-16T05:34:17.302Z</updated>
<content type="html"><![CDATA[<hr><p>这个 idea 来源于 <a href="https://www.cnblogs.com/mlystdcall/p/8078467.html">__stdcall 的教程合辑</a>, 觉得这个很好, 所以学习了.</p><span id="more"></span><p><del>Hexo 博客的强制置顶</del></p><h4 id="树状数组"><a href="#树状数组" class="headerlink" title="树状数组"></a>树状数组</h4><ul><li><p>树状数组进阶</p><ul><li><a href="https://www.cnblogs.com/RabbitHu/p/BIT.html">https://www.cnblogs.com/RabbitHu/p/BIT.html</a></li></ul></li></ul><h4 id="网络流"><a href="#网络流" class="headerlink" title="网络流"></a>网络流</h4><ul><li><p>网络流入门</p><ul><li><a href="https://www.xht37.com/二分图与网络流-学习笔记/">https://www.xht37.com/二分图与网络流-学习笔记/</a></li></ul></li><li><p>上下界网络流</p><ul><li><a href="https://www.cnblogs.com/mlystdcall/p/6734852.html">https://www.cnblogs.com/mlystdcall/p/6734852.html</a></li></ul></li><li><p>基于 Capacity Scaling 的弱多项式复杂度最小费用流算法</p><ul><li><a href="https://ouuan.github.io/post/%E5%9F%BA%E4%BA%8E-capacity-scaling-%E7%9A%84%E5%BC%B1%E5%A4%9A%E9%A1%B9%E5%BC%8F%E5%A4%8D%E6%9D%82%E5%BA%A6%E6%9C%80%E5%B0%8F%E8%B4%B9%E7%94%A8%E6%B5%81%E7%AE%97%E6%B3%95/">https://ouuan.github.io/post/基于-capacity-scaling-的弱多项式复杂度最小费用流算法</a></li></ul></li><li><p>模拟费用流</p><ul><li><a href="https://www.mina.moe/archives/11762">https://www.mina.moe/archives/11762</a></li></ul></li></ul><h4 id="线性基"><a href="#线性基" class="headerlink" title="线性基"></a>线性基</h4><ul><li><p>基础构造</p><ul><li><a href="https://oi.men.ci/linear-basis-notes/">https://oi.men.ci/linear-basis-notes/</a></li></ul></li><li><p>可重集 Kth 异或和</p><ul><li><a href="https://blog.csdn.net/qaq__qaq/article/details/53812883">https://blog.csdn.net/qaq__qaq/article/details/53812883</a></li><li><a href="https://ouuan.github.io/post/%E7%BA%BF%E6%80%A7%E5%9F%BA%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">https://ouuan.github.io/post/线性基学习笔记/</a></li></ul></li></ul><h4 id="动态规划"><a href="#动态规划" class="headerlink" title="动态规划"></a>动态规划</h4><ul><li><p>四边形不等式优化</p><ul><li><a href="https://oi-wiki.org/dp/opt/quadrangle/">https://oi-wiki.org/dp/opt/quadrangle/</a></li></ul></li></ul><h4 id="Link-Cut-Tree"><a href="#Link-Cut-Tree" class="headerlink" title="Link Cut Tree"></a>Link Cut Tree</h4><ul><li><p>应用 & 题单</p><ul><li><a href="https://www.cnblogs.com/flashhu/p/9498517.html">https://www.cnblogs.com/flashhu/p/9498517.html</a></li></ul></li></ul><h4 id="左偏树"><a href="#左偏树" class="headerlink" title="左偏树"></a>左偏树</h4><ul><li><p>特点及应用</p><ul><li><a href="https://files-cdn.cnblogs.com/files/shenben/算法合集之《左偏树的特点及其应用》.pdf">https://files-cdn.cnblogs.com/files/shenben/算法合集之《左偏树的特点及其应用》.pdf</a></li></ul></li></ul><h4 id="Min-Max-容斥"><a href="#Min-Max-容斥" class="headerlink" title="Min-Max 容斥"></a>Min-Max 容斥</h4><ul><li><p>证明及应用</p><ul><li><a href="https://www.cnblogs.com/GXZlegend/p/11563330.html">https://www.cnblogs.com/GXZlegend/p/11563330.html</a></li></ul></li></ul><h4 id="Stirling-数及-Stirling-反演"><a href="#Stirling-数及-Stirling-反演" class="headerlink" title="Stirling 数及 Stirling 反演"></a>Stirling 数及 Stirling 反演</h4><ul><li><p>性质及应用</p><ul><li><a href="https://www.cnblogs.com/y2823774827y/p/10700231.html">https://www.cnblogs.com/y2823774827y/p/10700231.html</a></li></ul></li></ul><h4 id="二项式反演"><a href="#二项式反演" class="headerlink" title="二项式反演"></a>二项式反演</h4><ul><li><p>证明及应用</p><ul><li><a href="https://www.cnblogs.com/GXZlegend/p/11407185.html">https://www.cnblogs.com/GXZlegend/p/11407185.html</a></li></ul></li></ul><h4 id="类欧几里得算法"><a href="#类欧几里得算法" class="headerlink" title="类欧几里得算法"></a>类欧几里得算法</h4><ul><li><p>推导及模板</p><ul><li><a href="https://oi-wiki.org/math/euclidean/">https://oi-wiki.org/math/euclidean/</a></li></ul></li></ul><h4 id="生成函数"><a href="#生成函数" class="headerlink" title="生成函数"></a>生成函数</h4><ul><li><p>生成函数的运算和常见模型</p><ul><li>金策, <生成函数的运算与组合计数问题>. 国家集训队 2015 论文集.</li></ul></li><li><p>图的计数</p><ul><li>汪乐平, <生成函数, 多项式算法与图的计数>. 2019.1.28.</li></ul></li></ul><hr>]]></content>
<summary type="html"><hr>
<p>这个 idea 来源于 <a href="https://www.cnblogs.com/mlystdcall/p/8078467.html">__stdcall 的教程合辑</a>, 觉得这个很好, 所以学习了.</p></summary>
<category term="笔记" scheme="https://depletedprism.github.io/categories/%E7%AC%94%E8%AE%B0/"/>
</entry>
<entry>
<title>一些积性函数相关的简单筛法</title>
<link href="https://depletedprism.github.io/memos/multiplicative-functions/"/>
<id>https://depletedprism.github.io/memos/multiplicative-functions/</id>
<published>2022-08-27T16:00:00.000Z</published>
<updated>2024-12-16T05:34:17.302Z</updated>
<content type="html"><![CDATA[<hr><p>useless algorithm 警告…</p><h2 id="综述"><a href="#综述" class="headerlink" title="综述"></a>综述</h2><p>记录了一些利用筛法求积性函数的方法.</p><span id="more"></span><h2 id="前置知识"><a href="#前置知识" class="headerlink" title="前置知识"></a>前置知识</h2><h3 id="数论函数"><a href="#数论函数" class="headerlink" title="数论函数"></a>数论函数</h3><p>数论函数指定义域为正整数, 陪域为复数的函数. 下面是几个常用的数论函数.</p><h4 id="幂函数"><a href="#幂函数" class="headerlink" title="幂函数"></a>幂函数</h4><script type="math/tex; mode=display">\operatorname{Id}_k(n) = n^k</script><p>特别地, 当 $k = 1$ 时, 记 $\operatorname{Id} = \operatorname{Id}_1(n) = n$.</p><h4 id="单位函数"><a href="#单位函数" class="headerlink" title="单位函数"></a>单位函数</h4><script type="math/tex; mode=display">\epsilon(n) = [n = 1]</script><p>其中 $[P]$ 在 $P$ 为真时值为 $1$, $P$ 为假时值为 $0$. </p><h4 id="常数函数"><a href="#常数函数" class="headerlink" title="常数函数"></a>常数函数</h4><script type="math/tex; mode=display">1(n) = 1</script><h3 id="积性函数"><a href="#积性函数" class="headerlink" title="积性函数"></a>积性函数</h3><p>若数论函数 $f$ 满足</p><ol><li><p>$f(1) = 1$.</p></li><li><p>当 $a$ 和 $b$ 互质 (也记作 $a\perp b$), 即 $\gcd(a, b) = 1$ 时, 有 $f(ab) = f(a)\cdot f(b)$.</p></li></ol><p>则称 $f$ 为积性函数. 特别地, 在此基础上如果 $f$ 还满足对于任意正整数 $a$, $b$ 均有 $f(ab) = f(a)\cdot f(b)$, 则称 $f$ 为完全积性函数.</p><h3 id="狄利克雷卷积"><a href="#狄利克雷卷积" class="headerlink" title="狄利克雷卷积"></a>狄利克雷卷积</h3><p>对于数论函数 $f$ 与 $g$, 若数论函数 $h$ 满足</p><script type="math/tex; mode=display">h(n) = \sum_{d|n}f(d) \cdot g\left(\frac{n}{d}\right)</script><p>则称 $h$ 为 $f$ 与 $g$ 的狄利克雷卷积, 记作 $h = f\ast g$.</p><p>狄利克雷卷积满足结合律, 交换律以及分配律. 此外, 对于任意数论函数 $f$ 有 $f\ast\epsilon = \epsilon\ast f = f$.</p><h2 id="埃氏筛-埃拉托斯特尼筛"><a href="#埃氏筛-埃拉托斯特尼筛" class="headerlink" title="埃氏筛 / 埃拉托斯特尼筛"></a>埃氏筛 / 埃拉托斯特尼筛</h2><p>假定现在需要得到 $1$ 到 $n$ 中的所有质数, 一个直接的筛法是从 $2$ 到 $n$ 枚举整数 $i$, 那么除去 $i$ 外的所有 $i$ 的倍数一定是合数. 如果枚举到 $i$ 时该数还没有被标记为合数, 那么 $i$ 为合数. 根据调和级数这样做的时间复杂度为 $O(n\log n)$.</p><p>如果在上述过程中只枚举质数的倍数, 就可以得到埃氏筛. 由唯一分解定理可知这样做是对的. 埃氏筛的时间复杂度为</p><script type="math/tex; mode=display">O\left(n\sum_{k=1}^{\pi(n)}\frac{1}{p_k}\right) = O(n\log\log n)</script><p>证明可参考 <a href="https://oi-wiki.org/math/number-theory/sieve/#%E5%9F%83%E6%8B%89%E6%89%98%E6%96%AF%E7%89%B9%E5%B0%BC%E7%AD%9B%E6%B3%95">https://oi-wiki.org/math/number-theory/sieve/</a>.</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">eratosthenes</span><span class="params">(<span class="type">int</span> n)</span> </span>{</span><br><span class="line"> <span class="function">vector<<span class="type">int</span>> <span class="title">npr</span><span class="params">(n)</span>, pr</span>;</span><br><span class="line"> npr[<span class="number">1</span>] = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">2</span>; i < n; ++i) {</span><br><span class="line"> <span class="keyword">if</span> (!npr[i]) {</span><br><span class="line"> pr.<span class="built_in">push_back</span>(i);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">2</span> * i; j < n; j += i)</span><br><span class="line"> npr[j] = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>后文的 min_25 筛一定程度上是埃氏筛的拓展.</p><h2 id="欧拉筛"><a href="#欧拉筛" class="headerlink" title="欧拉筛"></a>欧拉筛</h2><p>仍然考虑如何得到 $1$ 到 $n$ 中的所有质数. 从 $2$ 到 $n$ 枚举整数 $i$, 并依次枚举小于等于 $i$ 的所有质数 $p$. 显然 $i\cdot p$ 一定是合数. 同时, 为了避免一个数被重复标记, 此处希望 $p$ 是 $i\cdot p$ 的最小质因子, 因此当 $i \bmod p = 0$ 时就停止枚举.</p><p>这就是欧拉筛. 考虑到每个合数只会被对应的最小质因子标记一次, 欧拉筛的时间复杂度为 $O(n)$.</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">euler</span><span class="params">(<span class="type">int</span> n)</span> </span>{</span><br><span class="line"> <span class="function">vector<<span class="type">int</span>> <span class="title">npr</span><span class="params">(n)</span>, pr</span>;</span><br><span class="line"> npr[<span class="number">1</span>] = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">2</span>; i < n; ++i) {</span><br><span class="line"> <span class="keyword">if</span> (!npr[i]) pr.<span class="built_in">push_back</span>(i);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j < (<span class="type">int</span>) pr.<span class="built_in">size</span>() && i * pr[j] < n; ++j) {</span><br><span class="line"> npr[i * pr[j]] = <span class="literal">true</span>;</span><br><span class="line"> <span class="comment">// pr[j] 是 i * pr[j] 的最小质因子</span></span><br><span class="line"> <span class="keyword">if</span> (i % pr[j] == <span class="number">0</span>) <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>一个重要的性质在于, 通过欧拉筛可以得到每个数的最小质因子. 凭借此点可以在 $O(n)$ 的时间复杂度内得到诸多积性函数前 $n$ 项的值. 譬如</p><h3 id="约数函数"><a href="#约数函数" class="headerlink" title="约数函数"></a>约数函数</h3><script type="math/tex; mode=display">\sigma_k(n) = \sum_{d|n}d^k</script><p>显然这一系列函数都是积性函数, 下面先来讨论 $k$ 为 $0$ 和 $1$ 的两种情况.</p><h4 id="约数个数函数"><a href="#约数个数函数" class="headerlink" title="约数个数函数"></a>约数个数函数</h4><p>当 $k=0$ 时, 常用 $d(n)$ 来表示 $\sigma_0(n)$. 此时 $d(n)$ 的含义是 $n$ 的约数个数.</p><script type="math/tex; mode=display">d(n) = \sigma_0(n) = \sum_{d|n}1</script><p>对于正整数 $n$, 由唯一分解定理设 $n$ 可表示为</p><script type="math/tex; mode=display">n = \prod_i p_i^{c_i}</script><p>其中 $p_i$ 为质数. 那么 $d(n)$ 可表示为</p><script type="math/tex; mode=display">d(n) = \prod_i (1 + c_i)</script><p>这就提供了一种计算 $d(n)$ 的方法, 设 $g(n)$ 表示 $n$ 的最小质因子对 $d(n)$ 的贡献, 也就是最小质因子的相应指数再加 $1$. 考虑欧拉筛的过程, 有</p><ul><li><p>$d(1) = 1$, $g(1) = 1$.</p></li><li><p>若 $i$ 为质数, 有 $d(i) = 2$, $g(i) = 2$.</p></li><li><p>若 $i$ 不为质数, 分两种情况讨论: </p><ul><li><p>$i \bmod p_j \neq 0$</p><p>此时 $p_j$ 为 $i\cdot p_j$ 的最小质因子, 且 $i\perp p_j$, 故有</p><script type="math/tex; mode=display">\begin{align*}g(i \cdot p_j) &= 2\\d(i \cdot p_j) &= d(p_j) \cdot d(i) = 2 \cdot d(i)\end{align*}</script></li><li><p>$i \bmod p_j = 0$</p><p>此时 $p_j$ 仍为 $i\cdot p_j$ 的最小质因子, 但对应的指数大于 $1$. 可以利用 $g(i)$ 来更新, 具体而言, 有 $g(i\cdot p_j) = g(i) + 1$. 根据上文的式子, $d(i)$ 和 $d(i \cdot p_j)$ 之间只有 $p_j$ 参与的部分存在不同. 因此有</p><script type="math/tex; mode=display">d(i \cdot p_j) = d(i)\ \frac{g(i \cdot p_j)}{g(i)}</script></li></ul></li></ul><p>另外, 有这样一个流传甚广的表格. 可以看到在 $n$ 很大的时候 $d(n)$ 并不是特别大. 其中的 $\omega(n)$ 表示 $n$ 的不同质因子的个数.</p><div style="text-align:center;"><img src="/images/multiplicative-functions/table.jpg" width="480" /> </div><h4 id="约数和函数"><a href="#约数和函数" class="headerlink" title="约数和函数"></a>约数和函数</h4><p>当 $k=1$ 时, 常用 $\sigma(n)$ 来表示 $\sigma_1(n)$. 此时 $\sigma(n)$ 的含义是 $n$ 的所有约数之和.</p><script type="math/tex; mode=display">\sigma(n) = \sigma_1(n) = \sum_{d|n}d</script><p>同 $d(n)$ 类似, 约数和 $\sigma(n)$ 可以表示为</p><script type="math/tex; mode=display">\sigma(n) = \prod_i(1+p_i^1+\cdots+p_i^{c_i})</script><p>记 $n$ 的最小质因子为 $p$, 对应指数为 $c$. 同样设 $g(n)$ 表示 $p$ 对答案的贡献. 则有</p><script type="math/tex; mode=display">g(n) = 1 + p + p^2 + \cdots + p^c</script><p>接下来的过程和 $d(n)$ 几乎相同. 同样的思路可以在 $k \ge 1$ 的情况下沿用. 实际上, 对于任意质数 $p$ 有</p><script type="math/tex; mode=display">\sigma_k(p^x) = 1 + p^{k\cdot 1} + p^{k\cdot 2} + \cdots + p^{k\cdot x} = \frac{(p^k)^{x+1} - 1}{p^k - 1}</script><p>凭借上式以及唯一分解定理就可以解决 $k\ge 1$ 的情况.</p><h3 id="欧拉函数"><a href="#欧拉函数" class="headerlink" title="欧拉函数"></a>欧拉函数</h3><p>记 $\varphi(n)$ 表示小于等于 $n$ 且同 $n$ 互质的正整数的个数. 即</p><script type="math/tex; mode=display">\varphi(n) = \sum_{k=1}^n [\gcd(k, n) = 1]</script><p>这个形式看不出什么性质, 接下来将进一步推导出一个同 $n$ 的质因数分解相关的形式. 考虑到对于任意质数 $p$, 有</p><script type="math/tex; mode=display">\varphi(p^k) = p^k - p^{k-1} = p^k\left(1 - \frac{1}{p}\right)</script><p>这是很好理解的. 若一个数同 $p$ 的某个幂次 $p^k$ 不互质, 这个数一定是 $p$ 的倍数, 同时在小于等于 $p^k$ 的范围内这个倍数存在 $p^{k-1}$ 个, 故 $\varphi(p^k) = p^k-p^{k-1}$.</p><p>又因为 $\varphi(n)$ 为积性函数, 故对于正整数 $n$, 有</p><script type="math/tex; mode=display">\varphi(n) = n \prod_i\left(1 - \frac{1}{p_i}\right)</script><p>接下来分情况讨论就好了, 讨论过程可以参考 $d(n)$.</p><h3 id="莫比乌斯函数"><a href="#莫比乌斯函数" class="headerlink" title="莫比乌斯函数"></a>莫比乌斯函数</h3><script type="math/tex; mode=display">\mu(n) =\begin{cases} 1 & n=1\\ (-1)^s & n = \prod_{i=1}^s p_i\\ 0 & \text{otherwise}\end{cases}</script><p>换言之, 对于 $n > 1$, 如果 $n$ 不含有平方因子, 那么 $\mu(n) = (-1)^s$, 其中 $s$ 表示 $n$ 不同质因子的个数; 如果 $n$ 含有平方因子, 那么 $\mu(n) = 0$.</p><p>同样地, 接下来分情况讨论就好了.</p><p>总而言之, 对于积性函数 $f$, 记 $n$ 的最小质因子为 $p$, 对应次数为 $c$, 且 $n \neq p^c$, 则 $p^c \perp n/p^c$, 因此 $f(n) = f(p^c)f(n/p^c)$. 借此就可以利用欧拉筛计算 $f$.</p><h2 id="杜教筛"><a href="#杜教筛" class="headerlink" title="杜教筛"></a>杜教筛</h2><p>杜教筛借助了狄利克雷卷积的一些性质, 可以在 $O(n^{2/3})$ 的时间复杂度内计算某些积性函数的前缀和.</p><h3 id="欧拉函数-1"><a href="#欧拉函数-1" class="headerlink" title="欧拉函数"></a>欧拉函数</h3><p>首先有性质 $\operatorname{Id} = \varphi\ast 1$. 这是因为</p><blockquote><p>考虑枚举 $1$ 到 $n$ 中每个整数 $k$ 和 $n$ 的最大公约数 $d$, 有</p><script type="math/tex; mode=display">\begin{align*}n &= \sum_{k=1}^n \sum_{d|n} [\gcd(k, n) = d] \\&= \sum_{d|n} \sum_{k=1}^{n/d} \left[\gcd\left(k, \frac{n}{d}\right) = 1\right] \\&= \sum_{d|n} \varphi\left(\frac{n}{d}\right) =\sum_{d|n}\varphi(d)\end{align*}</script></blockquote><p>此外也可以利用 $(\varphi\ast 1)(p^k) = p^k$ 以及 $\operatorname{Id}_k$ 的完全积性来证明.</p><p>记 $\phi(n) = \sum_{k=1}^n \varphi(k)$. 则</p><script type="math/tex; mode=display">\begin{align*}\sum_{k=1}^n k &= \frac{1}{2}n(n+1) \\&= \sum_{k = 1}^n \sum_{d|k}\varphi\left(\frac{k}{d}\right) \\&= \sum_{d = 1}^n \sum_{k=1}^{\lfloor\frac{n}{d}\rfloor}\varphi(k)= \sum_{d = 1}^n \phi\left(\left\lfloor\frac{n}{d}\right\rfloor\right)\end{align*}</script><p>因此</p><script type="math/tex; mode=display">\phi(n) = \frac{1}{2}n(n+1) - \sum_{d=2}^n \phi\left(\left\lfloor\frac{n}{d}\right\rfloor\right)</script><p>只需用利用 $\lfloor\frac{n}{d}\rfloor$ 的 $O(\sqrt n)$ 种不同就取值就能够计算出 $\phi(n)$, 可以用记忆化搜索来实现, 空间复杂度为 $O(\sqrt{n})$. 此外, 计算一处 $\phi(n)$ 的时间复杂度为 $O(\sqrt{n})$, 即数论分块合并答案的时间复杂度. 记总体的时间复杂度为 $T(n)$, 则</p><script type="math/tex; mode=display">\begin{align*}T(n) &= \sum_{k=1}^{\lfloor\sqrt{n}\rfloor} O(\sqrt{k}) + \sum_{k=1}^{\lfloor\sqrt{n}\rfloor}O\left(\sqrt{\left\lfloor\frac{n}{k}\right\rfloor}\right) \\&= O\left(\int_1^{\sqrt{n}}\left(\sqrt{x} + \sqrt{\frac{n}{x}}\right)\mathrm d x\right) = O(n^{3/4})\end{align*}</script><p>如果用欧拉筛预处理 $\phi$ 前 $S$ 项, 且 $S > \sqrt n$, 则有</p><script type="math/tex; mode=display">\begin{align*}T(n) &= O(S) + \sum_{k=1}^{n/S} O\left(\sqrt{\left\lfloor\frac{n}{k}\right\rfloor}\right)\\&= O\left(S + \int_1^{n/S} \sqrt{\frac{n}{x}}\mathrm dx\right) = O\left(S + \frac{n}{S^{1/2}}\right)\end{align*}</script><p>取 $S = n^{2/3}$, 则 $T(n) = O(n^{2/3})$, 此时的空间复杂度也是 $O(n^{2/3})$. 更为细致的复杂度分析可参考 <a href="https://riteme.site/blog/2018-9-11/time-space-complexity-dyh-algo.html">杜教筛的时空复杂度分析 - riteme.site</a>.</p><h3 id="莫比乌斯函数-1"><a href="#莫比乌斯函数-1" class="headerlink" title="莫比乌斯函数"></a>莫比乌斯函数</h3><p>对于莫比乌斯函数, 则有 $\epsilon = \mu\ast 1$. 下面分两种情况证明这个结论.</p><blockquote><p>当 $n = 1$ 时, 有 $\epsilon(1) = \mu(1) = 1$.</p><p>当 $n > 1$ 时, 有 $\epsilon(n) = 0$. 设 $n$ 有 $s$ 个不同质因子, 对于 $n$ 的约数 $d$, 如果 $d$ 能对和式的值产生贡献, 即 $\mu(d) \neq 0$, 则 $d$ 一定是若干 $n$ 的质因子的乘积. 枚举选择的质因子个数 $k$, 有</p><script type="math/tex; mode=display">\sum_{d|n} \mu(d) = \sum_{k=0}^s (-1)^k \binom{n}{k} = (1 - 1)^s = 0</script><p>综上有 $\epsilon = \mu \ast 1$.</p></blockquote><p>另外, 考虑到 $\epsilon \ast f = f$, 若 $g=f\ast 1$, 则有 $g\ast\mu=f\ast 1\ast\mu = f$, 即</p><script type="math/tex; mode=display">g(n) = \sum_{d|n}f(d) \iff f(n) = \sum_{d|n}g(d)\mu\left(\frac{n}{d}\right)</script><p>其实就是所谓的莫比乌斯反演.</p><p>记 $M(n) = \sum_{k=1}^n \mu(k)$, 利用</p><script type="math/tex; mode=display">\sum_{k=1}^n [k = 1] = 1 = \sum_{k=1}^n\sum_{d|k}\mu\left(\frac{k}{d}\right)</script><p>借助于分析 $\phi(n)$ 时同样的思路可以得到</p><script type="math/tex; mode=display">M(n) = 1 - \sum_{d=2}^n M\left(\left\lfloor\frac{n}{d}\right\rfloor\right)</script><h3 id="约数个数函数-1"><a href="#约数个数函数-1" class="headerlink" title="约数个数函数"></a>约数个数函数</h3><p>虽然有 $\sigma_k = \operatorname{Id}_k \ast 1$, 但是</p><script type="math/tex; mode=display">\sum_{k=1}^n \sigma_k(n) = \sum_{d=1}^n \left\lfloor\frac{n}{d}\right\rfloor \cdot d^k</script><p>直接数论分块就好了, 剩余部分就是正整数的 $k$ 次方和.</p><h3 id="稍微一般的形式"><a href="#稍微一般的形式" class="headerlink" title="稍微一般的形式"></a>稍微一般的形式</h3><p>对于数论函数 $f$ 与 $g$, 记 $F(n) = \sum_{k=1}^n f(k)$, 则</p><script type="math/tex; mode=display">\begin{align*}\sum_{k=1}^n \left(f \ast g\right)(k) &= \sum_{k=1}^n \sum_{d|k} g(d)\cdot f\left(\frac{k}{d}\right) \\&= \sum_{d = 1}^n g(d) \sum_{k=1}^{\lfloor\frac{n}{d}\rfloor} f(k)= \sum_{d = 1}^n g(d) \cdot F\left(\left\lfloor\frac{n}{d}\right\rfloor\right)\end{align*}</script><p>因此</p><script type="math/tex; mode=display">g(1)\cdot F(n) = \sum_{k=1}^n \left(f\ast g\right)(k) - \sum_{d=2}^n g(d)\cdot F\left(\left\lfloor\frac{n}{d}\right\rfloor\right)</script><p>在求 $\phi$ 与 $M$ 的过程中, $g$ 可以在 $O(1)$ 的时间复杂度内计算. 实际上, 如果 $f$, $g$, $f\ast g$ 三者的前缀和中存在两个可以在不劣于杜教筛的时间复杂度内计算, 就可以利用杜教筛计算第三个.</p><h2 id="Powerful-Number-筛"><a href="#Powerful-Number-筛" class="headerlink" title="Powerful Number 筛"></a>Powerful Number 筛</h2><p>高中的时候听都没听过的东西. 以及终于不是用人名来命名了…</p><p>咕咕咕…</p><h2 id="洲阁筛"><a href="#洲阁筛" class="headerlink" title="洲阁筛"></a>洲阁筛</h2><p>咕咕咕…</p><h2 id="min-25-筛"><a href="#min-25-筛" class="headerlink" title="min_25 筛"></a>min_25 筛</h2><p>咕咕咕…</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li>冯东宇, 基础数论, 洛谷 2019 年 OI 夏令营.</li><li>11Dimensions, 从 1 开始的数论, 洛谷 2019 年 OI 夏令营.</li><li>任之洲, 积性函数求和的几种方法, 国家集训队 2016 论文集.</li><li>OI wiki, <a href="https://oi-wiki.org/">https://oi-wiki.org/</a>.</li><li>riteme, 杜教筛的时空复杂度分析, <a href="https://riteme.site/blog/2018-9-11/time-space-complexity-dyh-algo.html">https://riteme.site/blog/2018-9-11/time-space-complexity-dyh-algo.html</a></li><li>铃悬, 铃悬的数学小讲堂——狄利克雷卷积与莫比乌斯反演, <a href="https://www.luogu.com.cn/blog/lx-2003/mobius-inversion">https://www.luogu.com.cn/blog/lx-2003/mobius-inversion</a>.</li></ul><hr>]]></content>
<summary type="html"><hr>
<p>useless algorithm 警告…</p>
<h2 id="综述"><a href="#综述" class="headerlink" title="综述"></a>综述</h2><p>记录了一些利用筛法求积性函数的方法.</p></summary>
<category term="笔记" scheme="https://depletedprism.github.io/categories/%E7%AC%94%E8%AE%B0/"/>
<category term="Number Theory" scheme="https://depletedprism.github.io/tags/Number-Theory/"/>
</entry>
<entry>
<title>博弈论初步:图上的游戏, Nim 游戏和 SG 定理</title>
<link href="https://depletedprism.github.io/memos/game-theory-introduction/"/>
<id>https://depletedprism.github.io/memos/game-theory-introduction/</id>
<published>2022-08-12T16:00:00.000Z</published>
<updated>2024-12-16T05:34:17.302Z</updated>
<content type="html"><![CDATA[<hr><blockquote><p>さぁ、ゲームをはじめよう<br>来吧,游戏开始了。</p><p>- NO GAME NO LIFE</p></blockquote><h2 id="综述"><a href="#综述" class="headerlink" title="综述"></a>综述</h2><p>在 OI/XCPC 的范畴中, 博弈论的题目往往是在研究公平组合游戏, 似乎称为组合博弈论会好一点, 是寻常意义下的博弈论的一部分.</p><p>本文由有向图游戏开始, 到 Nim 游戏和 SG 定理结束, 介绍了一些简单的博弈论相关的内容.</p><span id="more"></span><h2 id="有向图上的游戏"><a href="#有向图上的游戏" class="headerlink" title="有向图上的游戏"></a>有向图上的游戏</h2><p>给定一张任意的有向图 $G$, 允许 $G$ 中存在环. 初始状态下, 某个结点 $s$ 上存在一枚棋子. 记棋子当前位于的结点为 $u$, 每一次操作可以将棋子沿着以 $u$ 为起点, $v$ 为终点的有向边移动到 $v$. 现在两名玩家轮流操作, 规定无法进行操作的玩家胜利或者失败. 此外, 视能无限进行的情况为平局. 现在已知 $G$ 与 $s$, 两名玩家都使用最优策略, 判断先手是否必胜, 必败, 或者平局.</p><p>一个直观的结论为, 如果 $G$ 中不存在环, 即 $G$ 为有向无环图 (Directed Acyclic Graph, DAG), 那么就不存在平局的情况. 但如果 $G$ 中存在环, 却有可能不是平局. 感性理解就是当一名玩家选择让棋子在环上转圈时, 另一位玩家可能有更好的选择而并不需要陪着他转圈…</p><p>既然双方都采用最优策略, 后手可以看作是初始状态不同的先手. 因此只需关注结点是否为先手必胜或者必败就好了. 对于一个结点 $u$, 如果以 $u$ 为棋子的起点, 先手无论如何操作总会失败, 那么称 $u$ 为必败结点. 相应地有必胜结点和平局结点. 同时称一个结点能够到达的结点为该结点的后继结点. 那么有</p><ul><li>不存在后继的结点是必胜结点或者必败结点, 取决于规则的限制.</li><li>一个结点是必败结点, 当且仅当所有后继结点都是必胜结点.</li><li>一个结点是必胜结点, 当且仅当存在一个后继结点是必败结点.</li><li>如果一个结点既不是必败结点又不是必胜结点, 则为平局结点.</li></ul><p>反转 $G$ 中每条边的起点和终点, 从必败结点或者必胜结点开始 DFS, 根据上述条件依次判定就好了. 记 $G$ 的边数为 $m$, 则可以在 $O(m)$ 的时间复杂度内完成对所有点的判断.</p><h2 id="Nim-游戏"><a href="#Nim-游戏" class="headerlink" title="Nim 游戏"></a>Nim 游戏</h2><p>给定 $n$ 堆石子, 石子数分别为 $a_1, a_2, \ldots, a_n$. 每一次操作可以选择唯一一堆, 取出正整数个石子. 现在两名玩家轮流操作, 规定无法进行操作的玩家失败, 也就是取走最后一枚石子的玩家胜利. 显然此时不存在平局的情况. 判断先手必胜或者必败.</p><p>将石子序列看作一个状态, 每次操作看作一条有向边, 则得到一张 DAG. 当前状态的变化可以视作棋子在 DAG 上的移动, 于是可以利用有向图游戏来解决 Nim 游戏. 但直接建图然后 DFS 的时间复杂度过大, 并不可取.</p><p>事实上存在直接的结论. 记 $\oplus$ 表示异或, 当且仅当 $a_1 \oplus a_2 \oplus \cdots \oplus a_n = 0$ 时先手必败, 其余情况先手必胜. 借助于有向图游戏可以证明这个结论.</p><blockquote><p>首先, 最终状态 $(0, 0, \ldots, 0)$ 满足所有数异或和为 $0$ 且为先手必败态.</p><p>其次, 对于一个不全为 $0$ 的状态 $(a_1, a_2, \ldots, a_n)$, 记 $a_1 \oplus a_2 \oplus \cdots \oplus a_n = s$, 一次操作之后异或和更改为 $s’$. 只需证明 $s=0$ 状态的后继状态中 $s’$ 均不为 $0$, 以及 $s\neq 0$ 状态的后继状态中存在 $s’=0$ 的状态.</p><p>对于前者, 任选一个位置 $i$ 并将 $a_i$ 变为 $a_i’$. 由于 $a_i > a_i’$, 有</p><script type="math/tex; mode=display">s'=s\oplus a_i\oplus a_i' = a_i \oplus a_i'\neq 0</script><p>对于后者, 选择满足 $a_i > a_i\oplus s$ 的位置 $i$ 并将 $a_i$ 变为 $a_i\oplus s$ 即可, 此时有 $s’=0$. 根据异或的性质可以得出满足该条件的 $a_i$ 一定存在.</p></blockquote><h3 id="允许添加石子的-Nim-游戏"><a href="#允许添加石子的-Nim-游戏" class="headerlink" title="允许添加石子的 Nim 游戏"></a>允许添加石子的 Nim 游戏</h3><p>在 Nim 游戏的基础上添加一种操作: 选择唯一一堆石子, 加入正整数个石子. 每回合可以选择添加或去除操作中的一种, 同时不允许游戏无限地进行下去.</p><p>容易发现这个操作在不允许游戏无限进行的限制下是没有意义的. 因为接下来的玩家可以通过去除相同位置的等量石子来抵消掉添加石子的影响. 同时, 考虑到双方都采用最优策略, 添加石子不会影响状态的输赢.</p><p>所以, 对于允许添加石子的 Nim 游戏而言, 每个状态的后继状态中一定包含所有的由去除操作得到的状态, 而就由添加操作得到的状态而言, 其存在与否并不对当前状态的输赢产生影响, 可有可无. 后续在 SG 定理的证明中这一点会有体现.</p><h2 id="SG-定理"><a href="#SG-定理" class="headerlink" title="SG 定理"></a>SG 定理</h2><p>公平组合游戏 (Impartial Game), 也有人称作无偏博弈, 指满足以下条件的游戏.</p><ul><li>游戏存在两名玩家, 两者轮流操作直到游戏到达最终状态.</li><li>在无法进行操作时决定游戏的胜负.</li><li>两名玩家操作数均有限, 游戏将在有限次操作后以非平局结束.</li><li>对于一个状态, 玩家双方能够做出的决策只和状态有关而同游戏者无关. 即同一个状态下两者可以做的操作相同.</li><li>游戏中的操作不依赖于概率, 操作的结果都是确定的.</li></ul><p>显然 Nim 游戏就是一个公平组合游戏. 事实上, 通过 SG 定理 (Sprague-Grundy Theorem) 可以将任何公平组合游戏转化为 Nim 游戏, 这也就是 SG 定理的强大之处.</p><p>对于集合 $S$, 记 $\operatorname{mex}(S)$ 表示不在 $S$ 中的最小非负整数.</p><p>对于一个公平组合游戏中的状态 $x$, 设 $x$ 后继状态有 $y_1, y_2, \ldots, y_k$. 定义 $x$ 的 SG 函数 $\operatorname{SG}(x)$ 为</p><script type="math/tex; mode=display">\operatorname{SG}(x) = \operatorname{mex}(\operatorname{SG}(y_1),\ \operatorname{SG}(y_2),\ \ldots,\ \operatorname{SG}(y_k))</script><p>特别地, 如果 $x$ 不存在后继状态, 则 $x$ 为先手必败态, 有 $\operatorname{SG}(x) = 0$.</p><p>其中 $\operatorname{SG}(x)$ 也被称为 Nim 数, Grundy 值等. 状态 $x$ 可以视为包含个数为 $\operatorname{SG}(x)$ 的一堆石子的 Nim 游戏. 接下来将证明这一点</p><blockquote><p>可以用归纳法来证明.</p><p>对于不存在后继的状态 $x$, $\operatorname{SG}(x) = \operatorname{mex}(\varnothing) = 0$, 同时初始状态为 $0$ 的 Nim 游戏也是先手必败.</p><p>对于存在后继的状态 $x$, 假设定理对 $x$ 的后继 $y_1, y_2, \ldots, y_k$ 均成立, 现在需要证明定理对 $x$ 也成立.</p><p>记 $p = \operatorname{mex}(\operatorname{SG}(y_1), \operatorname{SG}(y_2), \ldots, \operatorname{SG}(y_k))$, 那么在后继状态中, 对于所有小于 $p$ 的状态, 均可以由 $p$ 通过去除石子的操作得到; 对于存在的大于 $p$ 的状态, 可以由 $p$ 通过添加石子的操作得到. 因此 $\operatorname{SG}(x) = p$.</p></blockquote><p>根据 SG 定理, 对于 $n$ 个同时进行且相互独立的公平组合游戏 $x_1, x_2, \ldots, x_n$, 每回合选择一个游戏进行一次操作, 那么当且仅当 $\operatorname{SG}(x_1) \oplus \operatorname{SG}(x_2) \oplus \cdots \oplus \operatorname{SG}(x_n) = 0$ 时先手必败, 否则先手必胜.</p><h3 id="应用"><a href="#应用" class="headerlink" title="应用"></a>应用</h3><h4 id="Crosses-crosses"><a href="#Crosses-crosses" class="headerlink" title="Crosses-crosses"></a>Crosses-crosses</h4><p>直接从 cp-algorithms.com 搬来的例子.</p><p><strong>题目链接</strong></p><ul><li><a href="https://cp-algorithms.com/game_theory/sprague-grundy-nim.html#crosses-crosses">https://cp-algorithms.com/game_theory/sprague-grundy-nim.html#crosses-crosses</a></li></ul><p><strong>题目大意</strong></p><p>给定一个 $1\times n$ 的网格图, 每次操作可以选择一个格子画 $\times$, 要求不能有两个 $\times$ 相邻. 已知 $n$, 问先手必败还是必胜.</p><p><strong>解题思路</strong></p><p>状态 $n$ 表示当前在 $1\times n$ 的网格上操作. 分别讨论 $\times$ 画在网格端点和中间的情况可以得到</p><script type="math/tex; mode=display">\operatorname{SG}(n) = \operatorname{mex}\left(\{ \operatorname{SG}(n-2)\} \cup \{ \operatorname{SG}(i-2)\oplus \operatorname{SG}(n-i-1) | 2\le i\le n-1\}\right)</script><p>直接计算的时间复杂度为 $O(n^2)$. 此外, $\operatorname{SG}(n)$ 从某一位开始以一定的长度循环, 开始位置和循环节都不大, 实际上可以做到 $O(1)$.</p><h4 id="CF1312F-Attack-on-Red-Kingdom"><a href="#CF1312F-Attack-on-Red-Kingdom" class="headerlink" title="CF1312F Attack on Red Kingdom"></a>CF1312F Attack on Red Kingdom</h4><p><strong>题目链接</strong></p><ul><li><a href="https://codeforces.com/problemset/problem/1312/F">https://codeforces.com/problemset/problem/1312/F</a></li></ul><p><strong>解题思路</strong></p><p>问题的关键在于判断先手操作后, 后手再进行操作时的局面是否是先手必败. 显然要用到 SG 函数.</p><p>首先城堡之间互相独立, 分别考虑每个城堡. 对于每个状态, 除去守军数量 $a_i$ 外, 额外记录一个标记 $c$ 表示当前城堡上一次所受攻击的种类. 这样就能递推计算出 $\operatorname{SG}(a_i, c)$ 的值.</p><p>同时, 考虑到 $1\le x,y,z \le 5$, $\operatorname{SG}(a_i, c)$ 从某个位置之后开始循环, 循环节的一个很松的上界为 $4^{15}$. 但实际上循环节并不大, 通过暴力可以得知循环节最大为 $36$. 每次暴力找到循环开始位置和循环节就好了.</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><a href="https://cp-algorithms.com/game_theory/games_on_graphs.html">https://cp-algorithms.com/game_theory/games_on_graphs.html</a></li><li><a href="https://cp-algorithms.com/game_theory/sprague-grundy-nim.html">https://cp-algorithms.com/game_theory/sprague-grundy-nim.html</a> </li><li><a href="https://oi-wiki.org/math/game-theory/impartial-game/">https://oi-wiki.org/math/game-theory/impartial-game/</a></li><li><a href="https://en.wikipedia.org/wiki/Impartial_game">https://en.wikipedia.org/wiki/Impartial_game</a></li></ul><hr>]]></content>
<summary type="html"><hr>
<blockquote>
<p>さぁ、ゲームをはじめよう<br>来吧,游戏开始了。</p>
<p>- NO GAME NO LIFE</p>
</blockquote>
<h2 id="综述"><a href="#综述" class="headerlink" title="综述"></a>综述</h2><p>在 OI/XCPC 的范畴中, 博弈论的题目往往是在研究公平组合游戏, 似乎称为组合博弈论会好一点, 是寻常意义下的博弈论的一部分.</p>
<p>本文由有向图游戏开始, 到 Nim 游戏和 SG 定理结束, 介绍了一些简单的博弈论相关的内容.</p></summary>
<category term="笔记" scheme="https://depletedprism.github.io/categories/%E7%AC%94%E8%AE%B0/"/>
<category term="Game Theory" scheme="https://depletedprism.github.io/tags/Game-Theory/"/>
</entry>
<entry>
<title>泰勒公式的施勒米尔希-洛希余项备忘录</title>
<link href="https://depletedprism.github.io/memos/taylors-theorem-remainder/"/>
<id>https://depletedprism.github.io/memos/taylors-theorem-remainder/</id>
<published>2022-08-07T16:00:00.000Z</published>
<updated>2024-12-16T05:34:17.302Z</updated>
<content type="html"><![CDATA[<hr><p>大一上学高数的时候室友就谈到这个东西, 当时没有注意, 后来…</p><div style="text-align:center;"><img src="/images/taylors-theorem-remainder/base.jpg" /> </div><span id="more"></span><h2 id="泰勒公式"><a href="#泰勒公式" class="headerlink" title="泰勒公式"></a>泰勒公式</h2><p>如果 $f(x)$ 在 $x_0$ 处具有 $n$ 阶导数, 那么存在 $x_0$ 的邻域 $U(x_0)$, 使得对于 $U(x_0)$ 内的任意 $x$, 有</p><script type="math/tex; mode=display">f(x) = f(x_0) + \frac{f'(x_0)}{1!}(x-x_0) + \cdots + \frac{f^{(n)}(x_0)}{n!}x^n + o\left((x-x_0)^n\right)</script><p>式中的 $o\left((x-x_0)^n\right)$ 也被称为佩亚诺余项.</p><h2 id="施勒米尔希-洛希余项"><a href="#施勒米尔希-洛希余项" class="headerlink" title="施勒米尔希-洛希余项"></a>施勒米尔希-洛希余项</h2><p>根据泰勒公式, 函数 $f(x)$ 可表示为一个 $n$ 次多项式 $p(x)$, 以及一个同 $n$ 相关的余项 $r_n(x)$, 即 $f(x) = p(x) + r_n(x)$. 因此</p><script type="math/tex; mode=display">\begin{align*}r_n(x) &= f(x) - p(x) \\&= f(x) - \sum_{k=0}^n \frac{f^{(k)}(x_0)}{k!}x^k\end{align*}</script><p>设</p><script type="math/tex; mode=display">\varphi(z) = f(x) - \sum_{k=0}^n \frac{f^{(k)}(z)}{k!}x^k</script><p>则有 $\varphi(x) = 0$, $\varphi(x_0) = r_n(x)$. 这样就可以通过 $\varphi(z)$ 来研究 $r_n(x)$了, 在接下来的步骤中这会很有用. 将 $\varphi(z)$ 对 $z$ 求导, 得到</p><script type="math/tex; mode=display">\varphi'(z) = -\frac{f^{(n+1)}(z)}{n!}(x-z)^n</script><p>任取函数 $\psi(x)$, 满足 $\psi(x)$ 在 $x_0$ 与 $x$ 之间连续且可导. 根据柯西中值定理, 有</p><script type="math/tex; mode=display">\frac{\varphi(x) - \varphi(x_0)}{\psi(x) - \psi(x_0)} = \frac{\varphi'(x_0+\theta(x-x_0))}{\psi'(x_0+\theta(x-x_0))} \quad (0<\theta<1)</script><p>故</p><script type="math/tex; mode=display">\begin{align*}r_n(x) &= \varphi(x_0) \\&= \frac{\psi(x) - \psi(x_0)}{\psi'(x_0+\theta(x-x_0))} \cdot \frac{f^{(n+1)}(x_0 + \theta(x-x_0))}{n!}(1-\theta)^n (x-x_0)^n \end{align*}</script><p>取 $\psi(z) = (x-z)^p$, 则 $\psi’(z) = p(x-z)^{p-1}$. 代入并化简后可以得到</p><script type="math/tex; mode=display">r_n(x) = \frac{f^{(n+1)}(x_0 + \theta(x-x_0))}{n!\ p}(1-\theta)^{n+1-p} (x-x_0)^{n+1}</script><p>这就是所谓的施勒米尔希-洛希余项. 通过改变 $p$ 的取值可以得到其他形式的余项. 具体而言, </p><p>取 $p = n + 1$ 可得到拉格朗日余项为</p><script type="math/tex; mode=display">r_n(x) = \frac{f^{(n+1)}(x_0 + \theta (x-x_0))}{(n+1)!} (x-x_0)^{n+1}</script><p>取 $p = 1$ 可得到柯西余项为</p><script type="math/tex; mode=display">r_n(x) = \frac{f^{(n+1)}(x_0 + \theta (x-x_0))}{n!} (1-\theta)^n (x-x_0)^{n+1}</script><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><a href="https://zhuanlan.zhihu.com/p/41444619">泰勒展开式的施勒米尔希-洛希余项 - 知乎</a></li></ul><hr>]]></content>
<summary type="html"><hr>
<p>大一上学高数的时候室友就谈到这个东西, 当时没有注意, 后来…</p>
<div style="text-align:center;"><img src="/images/taylors-theorem-remainder/base.jpg" /> </div></summary>
<category term="笔记" scheme="https://depletedprism.github.io/categories/%E7%AC%94%E8%AE%B0/"/>
<category term="Calculus" scheme="https://depletedprism.github.io/tags/Calculus/"/>
</entry>
<entry>
<title>牛顿二项式定理备忘录</title>
<link href="https://depletedprism.github.io/memos/binomial-theorem/"/>
<id>https://depletedprism.github.io/memos/binomial-theorem/</id>
<published>2022-08-04T16:00:00.000Z</published>
<updated>2024-12-16T05:34:17.302Z</updated>
<content type="html"><![CDATA[<hr><blockquote><p>数学就是用的时候不够用的东西 = =</p></blockquote><h2 id="综述"><a href="#综述" class="headerlink" title="综述"></a>综述</h2><p>牛顿二项式定理是对二项式定理的推广, 也有人称之为广义二项式定理.</p><p>刚开始看 <组合数学> 的时候见到这个东西, 以为没什么用, 后来…</p><span id="more"></span><h2 id="陈述"><a href="#陈述" class="headerlink" title="陈述"></a>陈述</h2><h3 id="二项式定理"><a href="#二项式定理" class="headerlink" title="二项式定理"></a>二项式定理</h3><p>对于正整数 $n$ 和任意 $x, y$, 有</p><script type="math/tex; mode=display">(x + y) ^ n = \sum_{k=0}^n\; \binom{n}{k} x^k y ^{n-k}</script><p>这就是最常见的二项式定理, 其中 $n$ 可以推广到任意实数, 即</p><h3 id="牛顿二项式定理"><a href="#牛顿二项式定理" class="headerlink" title="牛顿二项式定理"></a>牛顿二项式定理</h3><p>设 $\alpha$ 是实数, 对于所有满足 $0 \leq |x| < |y|$ 的 $x$, $y$, 有</p><script type="math/tex; mode=display">(x+y)^\alpha = \sum_{k=0}^\infty\; \binom{\alpha}{k} x^k y^{\alpha-k}</script><p>其中</p><script type="math/tex; mode=display">\binom{\alpha}{k} = \frac{\alpha (\alpha - 1) \cdots (\alpha - k + 1)}{k!}</script><h2 id="证明"><a href="#证明" class="headerlink" title="证明"></a>证明</h2><p>实际上同济版高等数学下册在幂级数的部分就证明了这个东西, 接下来的证明要求对泰勒公式, 幂级数及其敛散性有一定程度的了解, 证明本身和后文的应用也没有什么关系…</p><p>证明的大体思路为将 $(x+y)^\alpha$ 展开为 $x$ 的幂级数. 设 $f(x) = (x+y)^\alpha$, 考虑到 $f(x)$ 的 $n$ 阶导数 $f^{(n)}(x)$ 满足</p><script type="math/tex; mode=display">f^{(n)}(x) = \alpha(\alpha-1)\cdots(\alpha-n+1)\cdot(x+y)^{\alpha-n}</script><p>所以 $f(x)$ 对应幂级数为</p><script type="math/tex; mode=display">\binom{\alpha}{0}y^\alpha + \binom{\alpha}{1} xy^{\alpha-1} + \cdots + \binom{\alpha}{k}x^ky^{\alpha-k} + \cdots</script><p>由于 $0\le |x| < |y|$, 有</p><script type="math/tex; mode=display">\lim_{n\rightarrow\infty} \left|\frac{a_{n+1}}{a_n}\right| = \lim_{n\rightarrow\infty} \left|\frac{\alpha-n}{n+1}\right| \cdot \left|\frac{x}{y}\right| < 1</script><p>所以对于任何实数 $\alpha$, 这个幂级数收敛. 接下来需要证明展开式中的余项趋于 $0$. 记泰勒展开的柯西余项为 $r_n(x)$, 则</p><script type="math/tex; mode=display">\begin{align*}r_n(x) &= \frac{f^{(n+1)}(\theta x)}{n!} (1-\theta)^n x^{n+1} \\&= \frac{\alpha(\alpha-1)\cdots(\alpha-n)}{n!} (y+\theta x)^{\alpha-n-1}(1-\theta)^n x^{n+1}\end{align*}</script><p>其中 $0<\theta<1$. 记 $z=x/y$, 则 $0\le|z|<1$. 考虑到</p><script type="math/tex; mode=display">\begin{align*}|r_{n+1}(x)| &= |r_n(x)| \cdot \left|1-\frac{\alpha}{n+1}\right| \cdot \left|\frac{(1-\theta)x}{y+\theta x}\right| \\&\le |r_n(x)| \cdot \left|1-\frac{\alpha}{n+1}\right| \cdot \frac{|z|-\theta|z|}{1-\theta|z|} \\&< |r_n(x)| \cdot \left|1-\frac{\alpha}{n+1}\right|\end{align*}</script><p>不管 $\alpha$ 取何值, 总存在一个 $N$ 使得当 $n>N$ 时, 有 $|r_{n+1}(x)| < |r_n(x)|$. 故</p><script type="math/tex; mode=display">\lim_{n\rightarrow\infty}\left|r_n(x)\right| = 0</script><p>综上有</p><script type="math/tex; mode=display">\sum_{k=0}^\infty \binom{\alpha}{k} x^ky^{\alpha-k} =(x + y)^\alpha</script><p>用拉格朗日余项也能得到同样的结论, 虽然在处理 $\binom{\alpha}{n}$ 的时候要复杂一点. 此外还有避免讨论余项的方法, 详见同济版高等数学下册.</p><h2 id="简单应用"><a href="#简单应用" class="headerlink" title="简单应用"></a>简单应用</h2><p>在 20 年刚开始学生成函数的时候对无穷还没什么概念, 所以看到这个和式上的无穷的时候, <del>顷刻留下了感动的泪水</del>. 现在看来先学点高数再来看这一套东西会好一点.</p><h3 id="一些转换"><a href="#一些转换" class="headerlink" title="一些转换"></a>一些转换</h3><p>有些时候需要式中的无穷项求和, 但又希望指数是整数而非实数. 下面针对此种情况对定理做一些转换. 设 $z = \frac{x}{y}$, 那么上述定理可以转述为</p><blockquote><p>对于所有满足 $|z| < 1$ 的任意 $z$, 有</p><script type="math/tex; mode=display">(1+z) ^ \alpha = \sum_{k=0}^\infty\; \binom{\alpha}{k} z^k</script></blockquote><p>设 $n$ 为正整数, 取 $\alpha$ 为负整数 $-n$, 则</p><script type="math/tex; mode=display">\binom{\alpha}{k} = \binom{-n}{k} = \frac{-n (-n-1) \cdots (-n-k+1)}{k!} = (-1)^k \binom{n+k-1}{k}</script><p>所以</p><script type="math/tex; mode=display">(1+z)^{-n} = \frac{1}{(1+z)^n} = \sum_{k=0}^\infty\; (-1)^k \binom{n+k-1}{k} z^k</script><p>为了干掉那个 $-1$, 令 $-z$ 代替 $z$, 得</p><script type="math/tex; mode=display">(1-z)^{-n} = \frac{1}{(1-z)^n} = \sum_{k=0}^\infty\; \binom{n+k-1}{k} z^k</script><p>取 $n=1$, 有 $\binom{n+k-1}{k} = \binom{k}{k} = 1$, 所以</p><script type="math/tex; mode=display">\frac{1}{1-z} = \sum_{k=0}^\infty\; z^k = 1 + z + z^2 + z^3 + \cdots</script><p>类似地, 有</p><script type="math/tex; mode=display">\frac{1}{1+z} = \sum_{k=0}^\infty\; (-1)^k z^k = 1 - z + z^2 - z^3 \cdots</script><p>稍微总结一下.</p><blockquote><p>如果 $n$ 是正整数, $r$ 是非 $0$ 实数, 那么</p><script type="math/tex; mode=display">(1-rx)^{-n} = \sum_{k=0}^\infty\; \binom{-n}{k} (-rx)^k</script><p>或等价地, 有</p><script type="math/tex; mode=display">\frac{1}{(1-rx)^n} = \sum_{k=0}^\infty\; \binom{n+k-1}{k} r^k x^k</script><p>其中 $|x| < \frac{1}{|r|}$.</p></blockquote><h3 id="一些例子"><a href="#一些例子" class="headerlink" title="一些例子"></a>一些例子</h3><p>可能在生成函数有关的题目会用到这些东西吧…</p><script type="math/tex; mode=display">1 + x + x^2 + \cdots = \frac{1}{1-x} \\ 1 + x^2 + x^4 + \cdots = 1 + (x)^2 + (x^2)^2 + \cdots = \frac{1}{1 - x^2} \\x + x^2 + x^3 + \cdots = x\; (1 + x + x^2 + \cdots) = \frac{x}{1 - x} \\1 + x + x^2 + x^3 + x^4 = \frac{1 - x^5}{1-x}</script><p>最后一个式子似乎是乱入的, 不过还好是显然的, 直接通分验证即可</p><h3 id="例题"><a href="#例题" class="headerlink" title="例题"></a>例题</h3><h4 id="BZOJ-3028-食物"><a href="#BZOJ-3028-食物" class="headerlink" title="BZOJ 3028 食物"></a>BZOJ 3028 食物</h4><ul><li><a href="https://vjudge.net/problem/%E9%BB%91%E6%9A%97%E7%88%86%E7%82%B8-3028">https://vjudge.net/problem/黑暗爆炸-3028</a></li><li><a href="https://lydsy.com/JudgeOnline/problem.php?id=3028">https://lydsy.com/JudgeOnline/problem.php?id=3028</a></li></ul><p><del>乐色 OJ 什么都是权限题</del> = =</p><p>首先您要学会生成函数, 然后这就是一道裸题.</p><p>设答案序列对应的生成函数为 $g(x)$, 化简后得</p><script type="math/tex; mode=display">g(x) = \frac{x}{(1-x)^4} = x \sum_{k=0}^\infty\; \binom{k+3}{k} x^k = \sum_{k=0}^\infty\; \binom{k+2}{k-1} x^k</script><p>$g(x)$ 的第 $n$ 项系数即为答案. 具体而言, 为</p><script type="math/tex; mode=display">\binom{n+2}{n-1} = \binom{n+2}{3} = \frac{1}{6} n(n+1)(n+2)</script><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li>Richard A. Brualdi. 组合数学. 机械工业出版社, 2012.4.</li><li><a href="https://www.cnblogs.com/Asika3912333/p/11406614.html">广义牛顿二项式定理 - Asika391</a></li><li>同济大学数学系. 高等数学. 下册. 高等教育出版社, 2014.7.</li></ul><hr>]]></content>
<summary type="html"><hr>
<blockquote>
<p>数学就是用的时候不够用的东西 = =</p>
</blockquote>
<h2 id="综述"><a href="#综述" class="headerlink" title="综述"></a>综述</h2><p>牛顿二项式定理是对二项式定理的推广, 也有人称之为广义二项式定理.</p>
<p>刚开始看 &lt;组合数学&gt; 的时候见到这个东西, 以为没什么用, 后来…</p></summary>
<category term="笔记" scheme="https://depletedprism.github.io/categories/%E7%AC%94%E8%AE%B0/"/>
<category term="Combinatorics" scheme="https://depletedprism.github.io/tags/Combinatorics/"/>
</entry>
<entry>
<title>多项式与 FFT 备忘录</title>
<link href="https://depletedprism.github.io/memos/polynomial-FFT/"/>
<id>https://depletedprism.github.io/memos/polynomial-FFT/</id>
<published>2022-07-24T03:11:03.000Z</published>
<updated>2024-12-16T05:34:17.302Z</updated>
<content type="html"><![CDATA[<hr><p>很多两年前学过的东西已经忘了, 虽然很大一部分原因在于当时就没有学明白, 但还是有一种原有的认知落空的感觉.</p><h2 id="综述"><a href="#综述" class="headerlink" title="综述"></a>综述</h2><p>在 OI/XCPC 中, FFT 常用于加速卷积的计算. 此外, 配合牛顿迭代得到的一系列多项式算法提供了对生成函数进行快速运算的方法, 因此在许多计数问题中也 FFT 也很有用.</p><span id="more"></span><h2 id="定义与前置知识"><a href="#定义与前置知识" class="headerlink" title="定义与前置知识"></a>定义与前置知识</h2><h3 id="多项式和形式幂级数"><a href="#多项式和形式幂级数" class="headerlink" title="多项式和形式幂级数"></a>多项式和形式幂级数</h3><p>对于环 $R$, $a_1, a_2, \ldots, a_n \in R$ 且 $a_n \neq 0$, 称</p><script type="math/tex; mode=display">f(x) = \sum_{k=0}^n a_k x^k</script><p>为环 $R$ 上次数为 $n$ 的多项式 $f(x)$. 其中次数也称作度, 记作 $\deg f$.</p><p>如果允许无限项存在, 则可以得到 $R$ 上的形式幂级数</p><script type="math/tex; mode=display">f(x) = \sum_{k = 0}^\infty a_k x^k</script><p>环 $R$ 上的多项式构成了一个环, 记为 $R[x]$. 类似地, 环 $R$ 上的形式幂级数也构成了一个环, 记作 $R[[x]]$.</p><p>先来讨论在复数域 $\mathbb{C}$ 上的情况. 当然也可以是其他环.</p><h3 id="多项式的点值表示"><a href="#多项式的点值表示" class="headerlink" title="多项式的点值表示"></a>多项式的点值表示</h3><p>对于度数为 $n$ 的多项式 $f(x) = \sum_{k=0}^n a_kx^k$, 带入 $n+1$ 个点 $x_0, x_1, \ldots, x_n$ 可得到 $f(x)$ 对应的点值表示 $f(x_0), f(x_1), \ldots, f(x_n)$. 表示成矩阵形式为</p><script type="math/tex; mode=display">\begin{bmatrix}f(x_0) \\ f(x_1) \\ f(x_2) \\ \vdots \\ f(x_n)\end{bmatrix}=\begin{bmatrix}1 & x_0 & x_0^2 & \cdots & x_0^n \\1 & x_1 & x_1^2 & \cdots & x_1^n \\1 & x_2 & x_2^2 & \cdots & x_2^n \\\vdots & \vdots & \vdots & \ddots & \vdots \\1 & x_n & x_n^2 & \cdots & x_n^n\end{bmatrix}\begin{bmatrix}a_0 \\ a_1 \\ a_2 \\ \vdots \\ a_{n}\end{bmatrix}</script><p>如果这 $n+1$ 个点互不相同, 那么中间的矩阵可逆, 根据 $n+1$ 个点对 $(x_k, f(x_k))$ 就可以唯一确定 $f(x)$.</p><h3 id="卷积和循环卷积"><a href="#卷积和循环卷积" class="headerlink" title="卷积和循环卷积"></a>卷积和循环卷积</h3><p>对于一个长为 $n$ 的序列 $a$ 和一个长为 $m$ 的序列 $b$, 有 $a$ 和 $b$ 的卷积为</p><script type="math/tex; mode=display">c_k = \sum_{i+j=k}a_i b_j = \sum_{i=0}^k a_i b_{k-i} = \sum_{j=0}^k a_{k-j} b_j</script><p>卷积可以用来表示多项式相乘的结果. 如果把 $a$ 和 $b$ 分别看作多项式 $f(x)$ 和 $g(x)$ 的各项系数, 那么两多项式之积 $f(x)g(x)$ 可表示为</p><script type="math/tex; mode=display">f(x)g(x) = \sum_{i=0}^{n-1}\sum_{j=0}^{m-1} a_ib_jx^{i+j} = \sum_{k=0}^{n+m-2}\left(\sum_{i+j=k} a_ib_j\right)x^k = \sum_{k=0}^{n+m-2} c_kx^k</script><p>对于两个长度为 $n$ 的序列 $a$, $b$, 有 $a$ 和 $b$ 的循环卷积为</p><script type="math/tex; mode=display">c_k = \sum_{(i+j)\bmod n = k}a_i b_j = \sum_{i+j=k}a_i b_j + \sum_{i+j=n+k}a_i b_j</script><h3 id="离散傅里叶变换及其逆变换"><a href="#离散傅里叶变换及其逆变换" class="headerlink" title="离散傅里叶变换及其逆变换"></a>离散傅里叶变换及其逆变换</h3><p>离散傅里叶变换 (Discrete Fourier Transform, DFT) 将一个长为 $N$ 的序列 $x_{0}, x_{1}, \ldots, x_{N-1}$ 变换为一个长为 $N$ 的复数序列 $X_{0}, X_{1}, \ldots, X_{N-1}$. 具体而言</p><script type="math/tex; mode=display">X_k = \sum_{n = 0}^{N - 1} x_n e^{-i\frac{2\pi}{N}kn}</script><p>同时有逆变换 (Inverse Discrete Fourier Transform, IDFT)</p><script type="math/tex; mode=display">x_n = \frac{1}{N}\sum_{k = 0}^{N - 1} X_k e^{i\frac{2\pi}{N}kn}</script><p>逆变换的正确性可以通过代入验证.</p><p>记 $\omega_n = e^{i\frac{2\pi}{n}}$, 根据复数的性质 $1, \omega_n, \ldots, \omega_n^{n-1}$ 组成了方程 $x^n = 1$ 的 $n$ 个不同的根, 称这 $n$ 个根为单位根.</p><p>如果将 $x_n$ 看作多项式 $f(x)$ 的系数, 那么 $X_k$ 就是 $f(x)$ 在 $x = e^{-i\frac{2\pi}{N}n}$ 处的点值. 因此 DFT 可以理解为多项式在 $n$ 个单位根处的点值表示. 同时, 实现上在计算 DFT 时往往使用 $1, \omega_n, \ldots, \omega_n^{n-1}$, 而非它们的倒数.</p><h3 id="卷积定理"><a href="#卷积定理" class="headerlink" title="卷积定理"></a>卷积定理</h3><p>对于两个长度为 $n$ 的序列 $a$ 和 $b$, 记 $a$ 和 $b$ 的循环卷积为 $c$, 那么有</p><script type="math/tex; mode=display">\operatorname{IDFT}(\operatorname{DFT}(a) \cdot \operatorname{DFT}(b)) = c</script><p>也就是说, 对 $a$ 和 $b$ 分别做 DFT, 两个结果逐项相乘就得到 $\operatorname{DFT}(c)$, 再做一次 IDFT 就可以得到 $c$. </p><p>证明可以从 DFT 与多项式在 $n$ 个单位根处的点值表示的关系入手. 设以 $a$, $b$ 和 $c$ 作为各项系数的多项式分别为 $f(x)$, $g(x)$ 和 $h(x)$. 对于 $s\in \mathbb{Z}$, 有</p><script type="math/tex; mode=display">f(\omega_n^s)g(\omega_n^s) = \sum_{k=0}^{n-1}\left(\sum_{i+j=k} a_ib_j + \sum_{i+j=n+k} a_ib_j\right)(\omega_n^s)^k = h(w_n^s)</script><p>也就是说 $\operatorname{DFT}(a) \cdot \operatorname{DFT}(b) = \operatorname{DFT}(c)$. 等式两端同时做 IDFT 就得到卷积定理.</p><p>利用卷积定理得到的计算结果实际上是循环卷积, 而非卷积. 但实际上可以通过补 0 使 $a$ 和 $b$ 的项数变为 $2n$, 得到项数为 $2n$ 的 $c$. 此时的循环卷积相当于普通的卷积. 在 $a$ 和 $b$ 长度不同且需要计算卷积时同样可以这样做.</p><h2 id="快速傅里叶变换"><a href="#快速傅里叶变换" class="headerlink" title="快速傅里叶变换"></a>快速傅里叶变换</h2><p>快速傅里叶变换 (Fast Fourier Transform, FFT) 能够在 $O(n\log n)$ 的时间复杂度内实现 DFT/IDFT 的计算, 再利用卷积定理即可在 $O(n\log n)$ 的时间复杂度内计算卷积.</p><p>对于 $n\in\mathbb{N}_+$, $k\in\mathbb{Z}$, 单位根 $\omega_n$ 有性质 $\omega_n^k=\omega_{2n}^{2k}$, $\omega_{2n}^{k+n}=-\omega_{2n}^k$. 接下来的推导将用到这些性质.</p><p>出于简便考虑, 只讨论对长度为 2 的幂次的序列做 FFT 的情况. 其余情况可以通过补 0 让长度变为 2 的幂次.</p><p>先来讨论 DFT. 考虑分治, 将当前序列分作奇数项和偶数项, 假定已经得到了奇数项对应 DFT 的各项值 $g(\omega_n^k)$, 以及偶数项对应的各项值 $h(\omega_n^k)$. 现在需要合并两者得到 $f(\omega_{2n}^k)$. 具体有</p><script type="math/tex; mode=display">\begin{align*}f(\omega_{2n}^k) &= g(\omega_{2n}^{2k}) + \omega_{2n}^k \cdot h(\omega_{2n}^{2k}) \\&= g(\omega_n^k) + \omega_{2n}^k \cdot h(\omega_n^k)\end{align*}</script><script type="math/tex; mode=display">\begin{align*}f(\omega_{2n}^{k+n}) &= g(\omega_{2n}^{2k}) + \omega_{2n}^{k+n} \cdot h(\omega_{2n}^{2k}) \\&= g(\omega_n^k) - \omega_{2n}^k \cdot h(\omega_n^k)\end{align*}</script><p>对于 IDFT, 一个直观的做法是将代入的单位根替换为原来的倒数, 再将所有值除以序列的长度 $n$. 但还有另一种做法. 考虑单位根的周期性, 将后 $n-1$ 个元素翻转就等同于代入原有单位根的倒数. 翻转后再将所有值除以 $n$ 就好了.</p><p>此时就得到了一个可以用递归实现且时间复杂度为 $O(n\log n)$ 的算法. 但递归实现常数较大, 接下来利用一些技巧将其更改为非递归实现.</p><h3 id="蝴蝶变换-位逆序置换"><a href="#蝴蝶变换-位逆序置换" class="headerlink" title="蝴蝶变换 / 位逆序置换"></a>蝴蝶变换 / 位逆序置换</h3><p>每一个位置 $i$, 在递归的过程中位置 $i$ 最终到达的位置恰好是 $i$ 二进制下各位翻转后得到的数. 这个翻转后的值可以在 $O(n)$ 的时间内递推出来.</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">rev[<span class="number">0</span>] = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i < n; ++i) <span class="comment">// n = (1 << l)</span></span><br><span class="line"> rev[i] = (rev[i >> <span class="number">1</span>] >> <span class="number">1</span>) | ((i & <span class="number">1</span>) << (l - <span class="number">1</span>));</span><br></pre></td></tr></table></figure><p>借助于 <code>rev[i]</code> 就可以实现非递归的 FFT.</p><h3 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h3><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// UOJ #34</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><complex></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> Complex = complex<<span class="type">double</span>>;</span><br><span class="line"><span class="keyword">constexpr</span> <span class="type">int</span> LOG = <span class="number">18</span>, MAXN = <span class="number">1</span> << LOG | <span class="number">1</span>;</span><br><span class="line"><span class="keyword">constexpr</span> <span class="type">double</span> PI = <span class="built_in">acos</span>(<span class="number">-1.0</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> Poly {</span><br><span class="line"> <span class="type">int</span> rev[MAXN];</span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">init</span><span class="params">(<span class="type">int</span> lim, <span class="type">int</span> l)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i < lim; ++i)</span><br><span class="line"> rev[i] = (rev[i >> <span class="number">1</span>] >> <span class="number">1</span>) | ((i & <span class="number">1</span>) << (l - <span class="number">1</span>));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">FFT</span><span class="params">(Complex* f, <span class="type">int</span> lim, <span class="type">int</span> type)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i < lim; ++i)</span><br><span class="line"> <span class="keyword">if</span> (i < rev[i]) <span class="built_in">swap</span>(f[i], f[rev[i]]);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> mid = <span class="number">1</span>; mid < lim; mid <<= <span class="number">1</span>) {</span><br><span class="line"> Complex wn = <span class="built_in">exp</span>(<span class="built_in">Complex</span>(<span class="number">0.0</span>, PI / mid));</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < lim; i += mid << <span class="number">1</span>) {</span><br><span class="line"> Complex w = <span class="number">1.0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j < mid; ++j, w *= wn) {</span><br><span class="line"> Complex f0 = f[i+j], f1 = w * f[i+j+mid];</span><br><span class="line"> f[i+j] = f0 + f1, f[i+j+mid] = f0 - f1;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (type < <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < lim; ++i) f[i] /= lim;</span><br><span class="line"> <span class="built_in">reverse</span>(f + <span class="number">1</span>, f + lim);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, m;</span><br><span class="line">Complex f[MAXN], g[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d"</span>, &n, &m), ++n, ++m;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> x, i = <span class="number">0</span>; i < n; ++i)</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &x), f[i] = <span class="built_in">Complex</span>(x);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> x, i = <span class="number">0</span>; i < m; ++i)</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &x), g[i] = <span class="built_in">Complex</span>(x);</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> lim = <span class="number">1</span>, l = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> (lim < n + m - <span class="number">1</span>) lim <<= <span class="number">1</span>, ++l;</span><br><span class="line"> Poly::<span class="built_in">init</span>(lim, l), Poly::<span class="built_in">FFT</span>(f, lim, <span class="number">1</span>), Poly::<span class="built_in">FFT</span>(g, lim, <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < lim; ++i) f[i] = f[i] * g[i];</span><br><span class="line"> Poly::<span class="built_in">FFT</span>(f, lim, <span class="number">-1</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < n + m - <span class="number">1</span>; ++i)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%.0f%c"</span>, f[i].<span class="built_in">real</span>(), <span class="string">" \n"</span>[i == n + m - <span class="number">2</span>]);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="预处理单位根"><a href="#预处理单位根" class="headerlink" title="预处理单位根"></a>预处理单位根</h3><p>在代码实现中, 单位根的幂次被反复计算, 可以将这部分预处理出来. 在多次进行 DFT/IDFT 时可以带来明显的常数优化.</p><h2 id="快速数论变换"><a href="#快速数论变换" class="headerlink" title="快速数论变换"></a>快速数论变换</h2><p>数论变换 (Number Theoretic Transform, NTT) 是 DFT 在模质数 $p$ 意义下的域 $\mathbb{F}_p$ 上的情况, 对模数 $p$ 有一定要求. 不过很多人也把此种情况下的 FFT 直接称作 NTT.</p><p>常用的 NTT 模数满足 $p=a\cdot 2^{b} + 1$, 要求序列长度不超过 $2^b$. 记 $p$ 的原根为 $g$, 那么 $g^{\frac{p-1}{n}}$ 就相当于 $\omega_n$, 且具有相似的性质.</p><script type="math/tex; mode=display">\begin{align*}469762049 &= 7 \times 2^{26} + 1 \\998244353 &= 7\times 17\times 2^{23} + 1 \\1004535809 &= 479 \times 2^{21} + 1\end{align*}</script><p>是原根为 $3$ 的 NTT 模数. 写三模数 NTT 的时候可能都会用到.</p><h2 id="应用"><a href="#应用" class="headerlink" title="应用"></a>应用</h2><h3 id="加速卷积的计算"><a href="#加速卷积的计算" class="headerlink" title="加速卷积的计算"></a>加速卷积的计算</h3><p>后文的其他应用本质上也是将问题转化为卷积的计算, 从而利用 FFT 优化时间复杂度. 普通的卷积当然可以直接算, 下面是两个不那么显然的卷积.</p><script type="math/tex; mode=display">c_k = \sum_{i = k}^n a_{i - k} b_{i} \tag{1}</script><p>二项式反演中常出现的式子, 也有人把这个叫做减法卷积. 记 $j = n + k - i$, 则有</p><script type="math/tex; mode=display">c_k = \sum_{i = k}^n a_{n - j} b_{i} = \sum_{i+j=n+k} a_{n-j} b_i</script><p>反转 $a$ 得到 $a’$, $a’$ 与 $b$ 卷积的第 $n+k$ 项即为 $c_k$.</p><script type="math/tex; mode=display">c_k = \sum_{i=0}^n a_{i+k}b_i \tag{2}</script><p>同 (1) 类似, 记 $j = n - k - i$, 则有</p><script type="math/tex; mode=display">c_k = \sum_{i=0}^n a_{n-j} b_i = \sum_{i+j=n-k}a_{n-j} b_i</script><p>反转 $a$ 得到 $a’$, $a’$ 与 $b$ 卷积的第 $n-k$ 项即为 $c_k$.</p><h3 id="字符串匹配"><a href="#字符串匹配" class="headerlink" title="字符串匹配"></a>字符串匹配</h3><p>对于长为 $n$ 字符串 $s$, $s$ 在字符串 $t$ 的位置 $k$ 处完全匹配当且仅当</p><script type="math/tex; mode=display">\sum_{0 \le i < n} (s_i - t_{i+k}) ^ 2 = 0</script><p>展开后是卷积的形式, 利用 FFT 计算就好了.</p><h2 id="分治与-FFT"><a href="#分治与-FFT" class="headerlink" title="分治与 FFT"></a>分治与 FFT</h2><p>在 $g_{1\ldots n}$ 已知的情况下, 对于形同</p><script type="math/tex; mode=display">f_i = \sum_{j = 1}^i f_{i - j} g_j</script><p>的式子, 可以利用分治的技巧在 $O(n\log^2 n)$ 的时间复杂度计算 $f_{1\ldots n}$. 具体而言, 对于一段区间, 先计算左半区间的值, 然后将左半区间上值对右半区间的贡献累计到右半区间上, 再计算右半区间的值. 其实就是 CDQ 分治.</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">solve</span><span class="params">(<span class="type">int</span> l, <span class="type">int</span> r)</span> </span>{ <span class="comment">// [l, r]</span></span><br><span class="line"> <span class="keyword">if</span> (l == r) <span class="keyword">return</span>;</span><br><span class="line"> <span class="type">int</span> mid = (l + r) / <span class="number">2</span>;</span><br><span class="line"> <span class="built_in">solve</span>(l, mid);</span><br><span class="line"> Poly::<span class="built_in">Mul</span>(f + l, mid - l + <span class="number">1</span>, g, r - l + <span class="number">1</span>, h);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = mid + <span class="number">1</span>; i <= r; ++i)</span><br><span class="line"> f[i] = (f[i] + h[i - l]) % P;</span><br><span class="line"> <span class="built_in">solve</span>(mid + <span class="number">1</span>, r);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>另外, 这个式子比较特殊, 经过一定的转化可以得到利用多项式求逆计算的方法, 时间复杂度 $O(n\log n)$.</p><h2 id="多项式的运算"><a href="#多项式的运算" class="headerlink" title="多项式的运算"></a>多项式的运算</h2><p>记 $[x^k]f(x)$ 表示多项式 $f(x)$ 中 $x^k$ 的系数.</p><h3 id="模多项式"><a href="#模多项式" class="headerlink" title="模多项式"></a>模多项式</h3><p>首先介绍多项式除法. 对于多项式 $f(x)$ 和 $g(x)$, 如果存在多项式 $Q(x)$ 和 $R(x)$ 满足</p><script type="math/tex; mode=display">f(x) = Q(x) g(x) + R(x)</script><p>且 $\deg R < \deg g$. 那么这样的 $Q(x)$ 和 $R(x)$ 唯一, 并称 $Q(x)$ 是 $f(x)$ 除以 $g(x)$ 的商, $R(x)$ 为余数.</p><p>同时, 称 $f(x)$ 和 $R(x)$ 在模 $g(x)$ 意义下同余, 记作</p><script type="math/tex; mode=display">f(x) \equiv R(x) \pmod{g(x)}</script><p>一个显然的性质是, 对于 $g(x)$ 的根 $x_0$, 考虑到 $g(x_0) = 0$, 则一定会有</p><script type="math/tex; mode=display">f(x_0) = R(x_0)</script><p>特别地, 当 $g(x) = x^n - 1$ 时, 上式中的 $x_0$ 可以取单位根 $\omega_n$. 所以 DFT 和 IDFT 的可以理解为是在模 $x^n - 1$ 意义下的变换.</p><p>在后文的运算中往往只关注模 $x^n$ 时的结果, 形式上就是多项式系数的前 $n$ 项.</p><h3 id="多项式牛顿迭代"><a href="#多项式牛顿迭代" class="headerlink" title="多项式牛顿迭代"></a>多项式牛顿迭代</h3><p>已知多项式 $g(x)$, 多项式牛顿迭代提供了计算满足以下条件 $f(x)$ 的方法.</p><script type="math/tex; mode=display">g(f(x)) \equiv 0 \pmod{x^n}</script><p>考虑倍增. 当 $n=1$ 时, 单独计算满足 $[x^0]g(f(x)) = 0$ 的 $[x^0]f(x)$.</p><p>当 $n>1$ 时. 记 $f_0(x)$ 是在模 $x^n$ 意义下的结果. 假定 $f_0(x)$ 已知, 现在需要计算模 $x^{2n}$ 下的结果 $f(x)$. 对 $g(f(x))$ 在 $f_0(x)$ 处进行泰勒展开, 有</p><script type="math/tex; mode=display">g(f(x)) = \sum_{k=0}^\infty \frac{g^{(k)}(f_0(x))}{k!} (f(x) - f_0(x))^k\equiv 0\pmod{x^{2n}}</script><p>其中 $g^{(k)}(f_0(x))$ 指 $g(f(x))$ 对 $f(x)$ 求 $k$ 阶导.</p><p>又因为 $f(x) - f_0(x)$ 最低的非零项次数大于等于 $x^n$, 所以当 $k\ge2$ 时有</p><script type="math/tex; mode=display">(f(x) - f_0(x)) ^ k \equiv 0 \pmod{x^{2n}}</script><p>皆大欢喜. 保留 $k=0$ 和 $k=1$ 两项就好了. 整理后得到</p><script type="math/tex; mode=display">f(x)\equiv f_0(x) - \frac{g(f_0(x))}{g'(f_0(x))} \pmod{x^{2n}}</script><p>其中导数依旧是对 $f(x)$ 求导. 通过构造不同的 $g(f(x))$, 就可以实现不同的运算.</p><h3 id="多项式求逆"><a href="#多项式求逆" class="headerlink" title="多项式求逆"></a>多项式求逆</h3><p>已知多项式 $h(x)$, 求模 $x^m$ 下多项式的 $f(x)$, 满足 $h(x)f(x) \equiv 1 \pmod{x^m}$. 有时也把 $f(x)$ 记作 $h^{-1}(x)$.</p><p>首先 $[x^0]f(x) = \left([x^0]h(x)\right)^{-1}$. 令 $g(x) = f(x) - h^{-1}(x)$, 则有</p><script type="math/tex; mode=display">f(x)\equiv \left(2 - f_0(x) h(x)\right) f_0(x) \pmod{x^{2n}}</script><p>倍增计算就好了, 时间复杂度 $O(n\log n)$.</p><h3 id="多项式开方"><a href="#多项式开方" class="headerlink" title="多项式开方"></a>多项式开方</h3><p>已知多项式 $h(x)$, 求模 $x^m$ 下多项式的 $f(x)$, 满足 $f^2(x) \equiv h(x) \pmod{x^m}$. 有时也把 $f(x)$ 记作 $\sqrt{h(x)}$.</p><p>如果是在 $\mathbb{F}_p$ 中考虑, $[x^0]f(x)$ 可以通过计算模 $p$ 下的二次剩余得到. 令 $g(x) = f^2(x) - h(x)$, 则有</p><script type="math/tex; mode=display">f(x)\equiv \frac{1}{2}\left(f_0(x) + \frac{h(x)}{f_0(x)}\right)\pmod{x^{2n}}</script><p>倍增计算就好了, 时间复杂度 $O(n\log n)$.</p><h3 id="多项式对数函数"><a href="#多项式对数函数" class="headerlink" title="多项式对数函数"></a>多项式对数函数</h3><p>对于多项式 $A(x) = \sum_{k\ge 1} a_kx^k$, 定义多项式对数函数</p><script type="math/tex; mode=display">\ln(1 - A(x)) = -\sum_{k\ge 1} \frac{A^k(x)}{k}</script><p>如果多项式 $h(x)$ 满足 $[x^0]h(x) = 1$, 那么有</p><script type="math/tex; mode=display">\ln h(x) = \int\frac{h'(x)}{h(x)} \mathrm{d}x</script><p>如果在积分时线性预处理逆元, 那么时间复杂度为 $O(n)$.</p><h3 id="多项式指数函数"><a href="#多项式指数函数" class="headerlink" title="多项式指数函数"></a>多项式指数函数</h3><p>对于多项式 $A(x) = \sum_{k\ge 1} a_kx^k$, 定义多项式指数函数</p><script type="math/tex; mode=display">\exp A(x) = \sum_{k\ge 0} \frac{A^k(x)}{k!}</script><p>已知多项式 $h(x)$, 满足 $[x^0]h(x) = 0$, 求模 $x^m$ 下的 $\exp h(x)$. 也就是求 $f(x)$, 满足 $\ln f(x) \equiv h(x) \pmod{x^m}$.</p><p>首先 $[x^0]f(x) = 1$. 令 $g(x) = \ln f(x) - h(x)$, 则有</p><script type="math/tex; mode=display">f(x)\equiv f_0(x)\left(1 - \ln f_0(x) + h(x)\right) \pmod{x^{2n}}</script><p>倍增计算就好了, 时间复杂度 $O(n\log n)$.</p><h3 id="多项式幂函数"><a href="#多项式幂函数" class="headerlink" title="多项式幂函数"></a>多项式幂函数</h3><p>当 $[x^0]f(x) = 1$ 时, 有</p><script type="math/tex; mode=display">f^k(x) \equiv \exp(k \ln f(x)) \pmod{x^n}</script><p>如果 $f(x)$ 在 $\mathbb{F}_p$ 上, 有 $f^p(x) = 1$. 在 $k$ 非常大的时候可能会用到.</p><p>当 $[x^0]f(x) \neq 0$ 时, 找到 $f(x)$ 次数最低的不为零项 $f_ix^i$, 将 $f_ix^i$ 提取出来就好了.</p><script type="math/tex; mode=display">f^k(x) \equiv \exp\left(k\ln\frac{f(x)}{f_i x^i}\right) \cdot (f_ix^i)^k\pmod{x^n}</script><p>时间复杂度 $O(n\log n)$.</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li>冯东宇, 多项式与 FFT, 洛谷 2019 年 OI 夏令营.</li><li><a href="https://oi-wiki.org">OI Wiki</a></li><li><a href="https://en.wikipedia.org/wiki/Discrete_Fourier_transform">Discrete Fourier transform - Wikipedia</a></li></ul><hr>]]></content>
<summary type="html"><hr>
<p>很多两年前学过的东西已经忘了, 虽然很大一部分原因在于当时就没有学明白, 但还是有一种原有的认知落空的感觉.</p>
<h2 id="综述"><a href="#综述" class="headerlink" title="综述"></a>综述</h2><p>在 OI/XCPC 中, FFT 常用于加速卷积的计算. 此外, 配合牛顿迭代得到的一系列多项式算法提供了对生成函数进行快速运算的方法, 因此在许多计数问题中也 FFT 也很有用.</p></summary>
<category term="笔记" scheme="https://depletedprism.github.io/categories/%E7%AC%94%E8%AE%B0/"/>
<category term="Polynomial" scheme="https://depletedprism.github.io/tags/Polynomial/"/>
</entry>
<entry>
<title>2021 年 ICPC 陕西省赛的部分题解</title>
<link href="https://depletedprism.github.io/sol/xcpc/2021-icpc-shaanxi/"/>
<id>https://depletedprism.github.io/sol/xcpc/2021-icpc-shaanxi/</id>
<published>2022-06-01T06:53:23.000Z</published>
<updated>2024-12-16T05:34:17.306Z</updated>
<content type="html"><![CDATA[<hr><p><strong>比赛链接</strong></p><ul><li>热身赛: <a href="https://ac.nowcoder.com/acm/contest/35520">https://ac.nowcoder.com/acm/contest/35520</a></li><li>现场赛: <a href="https://ac.nowcoder.com/acm/contest/35232">https://ac.nowcoder.com/acm/contest/35232</a></li></ul><p>铁牌作伴好还乡.</p><p>事实证明还是不要取一些诸如 “写的都不对” 之类的队名, 如果一语成谶就会非常尴尬 (</p><span id="more"></span><h2 id="热身赛"><a href="#热身赛" class="headerlink" title="热身赛"></a>热身赛</h2><h3 id="A-Square"><a href="#A-Square" class="headerlink" title="A Square"></a>A Square</h3><h4 id="解题思路"><a href="#解题思路" class="headerlink" title="解题思路"></a>解题思路</h4><p>当 $n$ 为 $2$, $3$ 或 $5$ 时结果为 <code>No</code>, 其余都是 <code>Yes</code>. <code>Yes</code> 的情况可以这样构造: 基于样例中 $n = 6$ 的情况, 在下面一行和靠右一行填入一个新的正方形, 这样可以覆盖 $4, 6, 8, \ldots$ 的情况. 对于奇数, 右下角换成 $2 \times 2$ 的正方形就好了, 可以覆盖 $7, 9, 11, \ldots$ 的情况.</p><h4 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// A</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="type">int</span> Ti;</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &Ti);</span><br><span class="line"> <span class="keyword">while</span> (Ti--) {</span><br><span class="line"> <span class="type">int</span> n;</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &n);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s\n"</span>, (n == <span class="number">2</span> || n == <span class="number">3</span> || n == <span class="number">5</span>)? <span class="string">"No"</span>: <span class="string">"Yes"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="B-CODE"><a href="#B-CODE" class="headerlink" title="B CODE"></a>B CODE</h3><h4 id="解题思路-1"><a href="#解题思路-1" class="headerlink" title="解题思路"></a>解题思路</h4><p>难点在于看懂题意 (</p><p>注意到至多有一处错误的条件. 得到原串至多修改一个位置的值, 而这个修改位置上的值一定导致, 二进制下为 1 每一位对应位置的值和给定值不同. 比如要修改位置 6, 那么位置 2 和位置 4 的值一定也会变化. 反过来, 如果计算出来有且只有位置 2 和位置 4 的值不匹配, 那么要修改的位置只可能是 6. 找到这个位置然后修改就好了.</p><h4 id="代码实现-1"><a href="#代码实现-1" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// B</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstring></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">constexpr</span> <span class="type">int</span> MAXN = <span class="number">1</span> << <span class="number">16</span> | <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> Ti, n;</span><br><span class="line"><span class="type">int</span> A[MAXN], B[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d"</span>, &Ti, &n);</span><br><span class="line"> <span class="keyword">while</span> (Ti--) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i < (<span class="number">1</span> << n); ++i)</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%1d"</span>, A + i);</span><br><span class="line"> <span class="built_in">memset</span>(B, <span class="number">0</span>, (<span class="number">1</span> << n) * <span class="built_in">sizeof</span>(<span class="type">int</span>));</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i < (<span class="number">1</span> << n); ++i) <span class="keyword">if</span> (i ^ (i & -i)) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">0</span>; k < n; ++k)</span><br><span class="line"> <span class="keyword">if</span> ((i >> k) & <span class="number">1</span>) B[<span class="number">1</span> << k] ^= A[i];</span><br><span class="line"> }</span><br><span class="line"> <span class="type">int</span> p = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < n; ++i)</span><br><span class="line"> <span class="keyword">if</span> (B[<span class="number">1</span> << i] != A[<span class="number">1</span> << i]) p |= (<span class="number">1</span> << i);</span><br><span class="line"> A[p] ^= <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i < (<span class="number">1</span> << n); ++i) <span class="built_in">printf</span>(<span class="string">"%d"</span>, A[i]);</span><br><span class="line"> <span class="built_in">putchar</span>(<span class="string">'\n'</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="C-Tree"><a href="#C-Tree" class="headerlink" title="C Tree"></a>C Tree</h3><h4 id="解题思路-2"><a href="#解题思路-2" class="headerlink" title="解题思路"></a>解题思路</h4><p>记 $f(u)$ 表示 $u$ 子树中的结点在这个子树中深度的最大值. 原树中一点 $u$ 的所有儿子, 在二叉树中一定是一条链. 直觉上让链上结点的 $f(v)$ 递减时答案是最优的, 排序然后贪心就好了.</p><p>时间复杂度 $O(n \log n)$.</p><h4 id="代码实现-2"><a href="#代码实现-2" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// C</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><vector></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">constexpr</span> <span class="type">int</span> MAXN = <span class="number">1e5</span> + <span class="number">5</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n;</span><br><span class="line">vector<<span class="type">int</span>> G[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> f[MAXN], T[MAXN][<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">dfs</span><span class="params">(<span class="type">int</span> u)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (G[u].<span class="built_in">size</span>() == <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">void</span>(f[u] = <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">auto</span> &v: G[u]) <span class="built_in">dfs</span>(v);</span><br><span class="line"> <span class="built_in">sort</span>(G[u].<span class="built_in">begin</span>(), G[u].<span class="built_in">end</span>(), [](<span class="type">int</span> i, <span class="type">int</span> j) {</span><br><span class="line"> <span class="keyword">return</span> f[i] > f[j] || (f[i] == f[j] && i < j);</span><br><span class="line"> });</span><br><span class="line"> T[u][<span class="number">0</span>] = *G[u].<span class="built_in">begin</span>();</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i + <span class="number">1</span> < G[u].<span class="built_in">size</span>(); ++i) {</span><br><span class="line"> <span class="type">int</span> v0 = G[u][i], v1 = G[u][i + <span class="number">1</span>];</span><br><span class="line"> T[v0][<span class="number">1</span>] = v1;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i < G[u].<span class="built_in">size</span>(); ++i) {</span><br><span class="line"> <span class="type">int</span> v = G[u][i];</span><br><span class="line"> f[u] = <span class="built_in">max</span>(f[u], f[v] + (<span class="type">int</span>) i + <span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &n);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> fa, u = <span class="number">2</span>; u <= n; ++u)</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &fa), G[fa].<span class="built_in">push_back</span>(u);</span><br><span class="line"> <span class="built_in">dfs</span>(<span class="number">1</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, f[<span class="number">1</span>]);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d %d\n"</span>, T[i][<span class="number">0</span>], T[i][<span class="number">1</span>]);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h2 id="正式赛"><a href="#正式赛" class="headerlink" title="正式赛"></a>正式赛</h2><h3 id="A-SegmentTree"><a href="#A-SegmentTree" class="headerlink" title="A SegmentTree"></a>A SegmentTree</h3><h4 id="解题思路-3"><a href="#解题思路-3" class="headerlink" title="解题思路"></a>解题思路</h4><p>首先代码的问题在于访问了线段树上每一个结点的左右儿子, 并认为数组越界了就算出错. 此时问题可转化为求解 $\frac{n(n+1)}{2}$ 个区间内有多少个区间在查询时会越界.</p><p>对于线段树上一个结点 $u$, 如果访问到 $u$ 时越界, 那么 $u$ 一定代表一个单独的位置, 将这个位置记作 $p$. 如果 $u$ 为父亲的左儿子, 那么所有以 $p$ 为右端点的区间在查询时都会越界, 因为一定会访问到 $u$. 同理, 如果是父亲的右儿子, 对应的则是以 $p$ 为左端点的区间. 据此计算可能越界的区间个数就好了.</p><p>记每组数据不满足条件的区间有 $x_i$ 个, 最终答案为</p><script type="math/tex; mode=display">\prod_{i = 1}^T \left(1 - \frac{x_i}{\frac{n_i (n_i + 1)}{2}}\right) ^ {q_i}</script><h4 id="代码实现-3"><a href="#代码实现-3" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// A</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> LL;</span><br><span class="line"><span class="keyword">constexpr</span> <span class="type">int</span> MAXN = <span class="number">1e5</span> + <span class="number">5</span>, P = <span class="number">1e9</span> + <span class="number">7</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">fpow</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span> </span>{</span><br><span class="line"> <span class="type">int</span> ret = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (b > <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">if</span> (b & <span class="number">1</span>) ret = (LL) ret * a % P;</span><br><span class="line"> a = (LL) a * a % P, b >>= <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, q;</span><br><span class="line"><span class="type">int</span> fr[MAXN], fl[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> SGT {</span><br><span class="line"><span class="meta">#<span class="keyword">define</span> lc (nd << 1)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> rc (nd << 1 | 1)</span></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">build</span><span class="params">(<span class="type">int</span> nd, <span class="type">int</span> L, <span class="type">int</span> R, <span class="type">bool</span> left)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (L == R) {</span><br><span class="line"> <span class="keyword">if</span> (nd >= <span class="number">2</span> * n)</span><br><span class="line"> left? ++fr[R]: ++fl[L];</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="type">int</span> Mid = (L + R) / <span class="number">2</span>;</span><br><span class="line"> <span class="built_in">build</span>(lc, L, Mid, <span class="literal">true</span>);</span><br><span class="line"> <span class="built_in">build</span>(rc, Mid + <span class="number">1</span>, R, <span class="literal">false</span>);</span><br><span class="line"> }</span><br><span class="line"><span class="meta">#<span class="keyword">undef</span> lc</span></span><br><span class="line"><span class="meta">#<span class="keyword">undef</span> rc</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="type">int</span> ti, ans = <span class="number">1</span>;</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &ti);</span><br><span class="line"> <span class="keyword">while</span> (ti--) {</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d"</span>, &n, &q);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">fill</span>(fr, fr + n + <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">fill</span>(fl, fl + n + <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line"> SGT::<span class="built_in">build</span>(<span class="number">1</span>, <span class="number">1</span>, n, <span class="literal">false</span>);</span><br><span class="line"> <span class="type">int</span> s = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) {</span><br><span class="line"> <span class="keyword">if</span> (fl[i] > <span class="number">0</span>) s = (s + n - i + <span class="number">1</span>) % P;</span><br><span class="line"> <span class="keyword">if</span> (fr[i] > <span class="number">0</span>) s = (s + i) % P;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i)</span><br><span class="line"> fl[i] = (fl[i - <span class="number">1</span>] + fl[i]) % P;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> r = <span class="number">1</span>; r <= n; ++r)</span><br><span class="line"> <span class="keyword">if</span> (fr[r] > <span class="number">0</span>)</span><br><span class="line"> s = (s - fl[r] + P) % P;</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> p = (<span class="number">1</span> - (LL) s * <span class="built_in">fpow</span>((LL) n * (n + <span class="number">1</span>) / <span class="number">2</span> % P, P - <span class="number">2</span>) % P + P) % P;</span><br><span class="line"> ans = (LL) ans * <span class="built_in">fpow</span>(p, q) % P;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, ans);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="C-GCD"><a href="#C-GCD" class="headerlink" title="C GCD"></a>C GCD</h3><h4 id="解题思路-4"><a href="#解题思路-4" class="headerlink" title="解题思路"></a>解题思路</h4><p>对于整数 $d$, 如果 $d$ 能成为 GCD 则区间 $[l, r]$ 内存在大于 $k$ 个 $d$ 的倍数. 即</p><script type="math/tex; mode=display">\lfloor \frac{r}{d} \rfloor - \lfloor \frac{l - 1}{d} \rfloor \geq k</script><p>利用数论分块计算就好了. 时间复杂度 $O(\sqrt{r})$.</p><h4 id="代码实现-4"><a href="#代码实现-4" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// C</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> LL;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> LL L, R, K, ans = <span class="number">0</span>;</span><br><span class="line"> cin >> L >> R >> K;</span><br><span class="line"> --L;</span><br><span class="line"> <span class="keyword">for</span> (LL d1 = <span class="number">1</span>, d2; d1 <= L; d1 = d2 + <span class="number">1</span>) {</span><br><span class="line"> d2 = <span class="built_in">min</span>(R / (R / d1), L / (L / d1));</span><br><span class="line"> <span class="keyword">if</span> (R / d1 - L / d1 >= K)</span><br><span class="line"> ans += d2 - d1 + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (LL d1 = L + <span class="number">1</span>, d2; d1 <= R; d1 = d2 + <span class="number">1</span>) {</span><br><span class="line"> d2 = R / (R / d1);</span><br><span class="line"> <span class="keyword">if</span> (R / d1 >= K)</span><br><span class="line"> ans += d2 - d1 + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> cout << ans << <span class="string">'\n'</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="D-Disease"><a href="#D-Disease" class="headerlink" title="D Disease"></a>D Disease</h3><h4 id="解题思路-5"><a href="#解题思路-5" class="headerlink" title="解题思路"></a>解题思路</h4><p>考虑枚举每一个深度 $d$, 然后计算 disaster value 为 $d$ 的概率. 此时需要保证, 深度等于 $d$ 的结点要么不感染, 要么感染之后不传给自己的父亲, 但一定存在一个已经感染的结点. 深度小于 $d$ 的结点不会自下而上地被感染, 保证其不会自发地感染就好了.</p><p>因此只需要关心向上的感染. 记 $f(u)$ 此种限制下 $u$ 被感染的概率, 则有</p><script type="math/tex; mode=display">f(u) = \frac{p_u}{q_u} + \left(1 - \frac{p_u}{q_u}\right) \prod_{v \in \mathrm{son}(u)}\left(1 - \frac{a}{b} f(v)\right)</script><p>记</p><script type="math/tex; mode=display">m(d) = \prod_{\mathrm{depth}(u) = d} \left( 1 - \frac{p_u}{q_u} \right)</script><p>同时记 $\mathrm{pre}(u)$ 表示结点 $u$ 到其父亲那条边对应的 $\frac{a}{b}$. 最后答案为</p><script type="math/tex; mode=display">\sum_{d} d \cdot \left(\prod_{\mathrm{depth}(u) = d} \Big( 1 - \mathrm{pre}(u) \cdot f(u) \Big) - \prod_{\mathrm{depth}(u)=d} \Big(1 - f(u)\Big) \right) \prod_{k = 1}^{d - 1} m(k)</script><p>预处理逆元之后的时间复杂度可以做到 $O(n)$, 不过多个快速幂的 log 也不影响什么.</p><h4 id="代码实现-5"><a href="#代码实现-5" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// D</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstring></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> LL;</span><br><span class="line"><span class="keyword">constexpr</span> <span class="type">int</span> MAXN = <span class="number">1e5</span> + <span class="number">5</span>, P = <span class="number">1e9</span> + <span class="number">7</span>;</span><br><span class="line"></span><br><span class="line"><span class="function">LL <span class="title">fpow</span><span class="params">(LL b, <span class="type">int</span> m)</span> </span>{</span><br><span class="line"> LL ret = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (m > <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">if</span> (m & <span class="number">1</span>) ret = ret * b % P;</span><br><span class="line"> b = b * b % P, m >>= <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, mxd;</span><br><span class="line">LL f[MAXN], g[MAXN], h[MAXN], p[MAXN], m[MAXN], pre[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> Graph {</span><br><span class="line"> <span class="keyword">struct</span> <span class="title class_">Edge</span> {</span><br><span class="line"> <span class="type">int</span> nxt, v, w;</span><br><span class="line"> } edges[MAXN << <span class="number">1</span>];</span><br><span class="line"> <span class="type">int</span> head[MAXN], eidx;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">init</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="built_in">memset</span>(head, <span class="number">-1</span>, <span class="keyword">sizeof</span> head), eidx = <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">addEdge</span><span class="params">(<span class="type">int</span> u, <span class="type">int</span> v, <span class="type">int</span> w)</span> </span>{</span><br><span class="line"> edges[++eidx] = (Edge){ head[u], v, w }, head[u] = eidx;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">dfs</span><span class="params">(<span class="type">int</span> u, <span class="type">int</span> fa, <span class="type">int</span> d)</span> </span>{</span><br><span class="line"> <span class="keyword">using</span> <span class="keyword">namespace</span> Graph;</span><br><span class="line"> mxd = <span class="built_in">max</span>(mxd, d);</span><br><span class="line"> LL s = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> v, i = head[u]; ~i; i = edges[i].nxt) {</span><br><span class="line"> <span class="keyword">if</span> ((v = edges[i].v) == fa) <span class="keyword">continue</span>;</span><br><span class="line"> pre[v] = edges[i].w;</span><br><span class="line"> <span class="built_in">dfs</span>(v, u, d + <span class="number">1</span>);</span><br><span class="line"> s = s * (<span class="number">1</span> - pre[v] * f[v] % P + P) % P;</span><br><span class="line"> }</span><br><span class="line"> f[u] = (p[u] + (<span class="number">1</span> - p[u] + P) % P * (<span class="number">1</span> - s + P) % P) % P;</span><br><span class="line"> g[d] = g[d] * (<span class="number">1</span> - pre[u] * f[u] % P + P) % P;</span><br><span class="line"> h[d] = h[d] * (<span class="number">1</span> - f[u] + P) % P;</span><br><span class="line"> m[d] = m[d] * (<span class="number">1</span> - p[u] + P) % P;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"D.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> Graph::<span class="built_in">init</span>();</span><br><span class="line"></span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &n);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> pu, qu, u = <span class="number">1</span>; u <= n; ++u) {</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d"</span>, &pu, &qu);</span><br><span class="line"> p[u] = (LL) pu * <span class="built_in">fpow</span>(qu, P - <span class="number">2</span>) % P;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> u, v, a, b, i = <span class="number">1</span>; i < n; ++i) {</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d%d%d"</span>, &u, &v, &a, &b);</span><br><span class="line"> <span class="type">int</span> w = (LL) a * <span class="built_in">fpow</span>(b, P - <span class="number">2</span>) % P;</span><br><span class="line"> Graph::<span class="built_in">addEdge</span>(u, v, w), Graph::<span class="built_in">addEdge</span>(v, u, w);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> d = <span class="number">0</span>; d <= n; ++d)</span><br><span class="line"> g[d] = h[d] = m[d] = <span class="number">1</span>;</span><br><span class="line"> <span class="built_in">dfs</span>(<span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"> LL ans = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> d = <span class="number">1</span>; d <= mxd; ++d) {</span><br><span class="line"> ans = (ans + (g[d] - h[d] + P) % P * m[d - <span class="number">1</span>] % P * d % P) % P;</span><br><span class="line"> m[d] = m[d - <span class="number">1</span>] * m[d] % P;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%lld\n"</span>, ans);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="E-swapping-game"><a href="#E-swapping-game" class="headerlink" title="E swapping game"></a>E swapping game</h3><h4 id="解题思路-6"><a href="#解题思路-6" class="headerlink" title="解题思路"></a>解题思路</h4><p>对 $q$ 分奇偶讨论. 对于奇数, 随着操作次数的增加, $q$ 一直向右移动, 到位置 $n$ 后改向左移动, 直到位置 $1$, 周而复始且周期为 $2n$. 偶数则类似. 根据 $k$ 的大小分类讨论就好了.</p><h4 id="代码实现-6"><a href="#代码实现-6" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// E</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="type">int</span> Ti;</span><br><span class="line"> cin >> Ti;</span><br><span class="line"> <span class="keyword">while</span> (Ti--) {</span><br><span class="line"> <span class="type">int</span> n, k, q;</span><br><span class="line"> cin >> n >> k >> q;</span><br><span class="line"> k %= <span class="number">2</span> * n;</span><br><span class="line"> <span class="keyword">if</span> (q & <span class="number">1</span>) {</span><br><span class="line"> <span class="keyword">if</span> (k <= n - q) {</span><br><span class="line"> cout << q + k << <span class="string">'\n'</span>;</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (k <= <span class="number">2</span> * n - q) {</span><br><span class="line"> cout << n - (k - (n - q)) + <span class="number">1</span> << <span class="string">'\n'</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> cout << k - (<span class="number">2</span> * n - q) << <span class="string">'\n'</span>;</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">if</span> (k <= q - <span class="number">1</span>) {</span><br><span class="line"> cout << q - k << <span class="string">'\n'</span>;</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (k <= n + q - <span class="number">1</span>) {</span><br><span class="line"> cout << k - (q - <span class="number">1</span>) << <span class="string">'\n'</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> cout << n - (k - (n + q - <span class="number">1</span>)) + <span class="number">1</span> << <span class="string">'\n'</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="I-Rabbit"><a href="#I-Rabbit" class="headerlink" title="I Rabbit"></a>I Rabbit</h3><h4 id="解题思路-7"><a href="#解题思路-7" class="headerlink" title="解题思路"></a>解题思路</h4><p>首先考虑 $a_i$ 中含有 0 的情况. 显然, 当 0 数量大于 1 时无论去除哪个数 Cute Value 都是 0, 当 0 数量为 1 时只有去掉 0 才能改变 Cute Value, 因此这两种情况的答案分别为 0, 1.</p><p>对于 $a_i$ 中不含 0 的情况, 统计 1 的出现次数 $c_1$, 答案即为 $n - c_1$.</p><h4 id="代码实现-7"><a href="#代码实现-7" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// I</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">constexpr</span> <span class="type">int</span> MAXN = <span class="number">1e5</span> + <span class="number">5</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n;</span><br><span class="line"><span class="type">int</span> A[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &n);</span><br><span class="line"> <span class="type">int</span> c0 = <span class="number">0</span>, c1 = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) {</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, A + i);</span><br><span class="line"> <span class="keyword">if</span> (A[i] == <span class="number">0</span>) ++c0;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (c0 == <span class="number">0</span>) {</span><br><span class="line"> <span class="built_in">sort</span>(A + <span class="number">1</span>, A + <span class="number">1</span> + n);</span><br><span class="line"> n = <span class="built_in">unique</span>(A + <span class="number">1</span>, A + <span class="number">1</span> + n) - A - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i)</span><br><span class="line"> <span class="keyword">if</span> (A[i] == <span class="number">1</span>) ++c1;</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, n - c1);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, c0 == <span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="J-Cube"><a href="#J-Cube" class="headerlink" title="J Cube"></a>J Cube</h3><h4 id="解题思路-8"><a href="#解题思路-8" class="headerlink" title="解题思路"></a>解题思路</h4><p>模拟就好了.</p><h4 id="代码实现-8"><a href="#代码实现-8" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// J</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><vector></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">pii</span> {</span><br><span class="line"> <span class="type">int</span> a, b;</span><br><span class="line"></span><br><span class="line"> <span class="built_in">pii</span>() = <span class="keyword">default</span>;</span><br><span class="line"> <span class="built_in">pii</span>(<span class="type">int</span> _a, <span class="type">int</span> _b) {</span><br><span class="line"> <span class="keyword">if</span> (_a > _b) <span class="built_in">swap</span>(_a, _b);</span><br><span class="line"> a = _a, b = _b;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="type">bool</span> <span class="keyword">operator</span> < (<span class="type">const</span> pii &rhs) <span class="type">const</span> {</span><br><span class="line"> <span class="keyword">return</span> a < rhs.a || (a == rhs.a && b < rhs.b);</span><br><span class="line"> }</span><br><span class="line"> <span class="type">bool</span> <span class="keyword">operator</span> != (<span class="type">const</span> pii &rhs) <span class="type">const</span> {</span><br><span class="line"> <span class="keyword">return</span> *<span class="keyword">this</span> < rhs || rhs < *<span class="keyword">this</span>;</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Cube</span> {</span><br><span class="line"> vector<pii> v;</span><br><span class="line"></span><br><span class="line"> <span class="built_in">Cube</span>() = <span class="keyword">default</span>;</span><br><span class="line"> <span class="built_in">Cube</span>(vector<pii> _v) {</span><br><span class="line"> <span class="built_in">sort</span>(_v.<span class="built_in">begin</span>(), _v.<span class="built_in">end</span>()), v = _v;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="type">bool</span> <span class="keyword">operator</span> == (<span class="type">const</span> Cube& rhs) <span class="type">const</span> {</span><br><span class="line"> <span class="keyword">if</span> (v.<span class="built_in">size</span>() != rhs.v.<span class="built_in">size</span>())</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i < v.<span class="built_in">size</span>(); ++i)</span><br><span class="line"> <span class="keyword">if</span> (v[i] != rhs.v[i]) <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="function">Cube <span class="title">convert</span><span class="params">(<span class="type">const</span> vector<<span class="type">int</span>> &v)</span> </span>{</span><br><span class="line"> pii a = <span class="built_in">pii</span>(v[<span class="number">4</span>], v[<span class="number">6</span>]), b = <span class="built_in">pii</span>(v[<span class="number">5</span>], (v[<span class="number">7</span>] > <span class="number">0</span>)? v[<span class="number">7</span>]: v[<span class="number">11</span>]);</span><br><span class="line"> <span class="type">int</span> c1 = <span class="number">0</span>, c2 = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i < <span class="number">4</span>; ++i)</span><br><span class="line"> <span class="keyword">if</span> (v[i] > <span class="number">0</span>) { c1 = v[i]; <span class="keyword">break</span>; }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">8</span>; i < <span class="number">12</span>; ++i)</span><br><span class="line"> <span class="keyword">if</span> (v[i] > <span class="number">0</span>) { c2 = v[i]; <span class="keyword">break</span>; }</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Cube</span>({a, b, <span class="built_in">pii</span>(c1, c2)});</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="function">vector<<span class="type">int</span>> <span class="title">c0</span><span class="params">(<span class="number">12</span>)</span>, <span class="title">c1</span><span class="params">(<span class="number">12</span>)</span></span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i < <span class="number">12</span>; ++i)</span><br><span class="line"> cin >> c0[i];</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i < <span class="number">12</span>; ++i)</span><br><span class="line"> cin >> c1[i];</span><br><span class="line"> cout << ((<span class="built_in">convert</span>(c0) == <span class="built_in">convert</span>(c1))? <span class="string">"YES"</span>: <span class="string">"NO"</span>) << <span class="string">'\n'</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><hr>]]></content>
<summary type="html"><hr>
<p><strong>比赛链接</strong></p>
<ul>
<li>热身赛: <a href="https://ac.nowcoder.com/acm/contest/35520">https://ac.nowcoder.com/acm/contest/35520</a></li>
<li>现场赛: <a href="https://ac.nowcoder.com/acm/contest/35232">https://ac.nowcoder.com/acm/contest/35232</a></li>
</ul>
<p>铁牌作伴好还乡.</p>
<p>事实证明还是不要取一些诸如 “写的都不对” 之类的队名, 如果一语成谶就会非常尴尬 (</p></summary>
<category term="题解" scheme="https://depletedprism.github.io/categories/%E9%A2%98%E8%A7%A3/"/>
</entry>
<entry>
<title>2022 年西安电子科技大学校赛的部分题解</title>
<link href="https://depletedprism.github.io/sol/xcpc/2022-xdu-campus/"/>
<id>https://depletedprism.github.io/sol/xcpc/2022-xdu-campus/</id>
<published>2022-05-25T10:57:21.000Z</published>
<updated>2024-12-16T05:34:17.306Z</updated>
<content type="html"><![CDATA[<hr><p><strong>题目 & 题面</strong></p><ul><li><a href="https://acm.xidian.edu.cn/contest.php?cid=1083">https://acm.xidian.edu.cn/contest.php?cid=1083</a></li><li><a href="https://acm.xidian.edu.cn/campus/2022/statements.pdf">https://acm.xidian.edu.cn/campus/2022/statements.pdf</a></li></ul><p>被出题人打爆了.</p><span id="more"></span><h2 id="现场赛"><a href="#现场赛" class="headerlink" title="现场赛"></a>现场赛</h2><h3 id="D-数位相邻"><a href="#D-数位相邻" class="headerlink" title="D 数位相邻"></a>D 数位相邻</h3><h4 id="解题思路"><a href="#解题思路" class="headerlink" title="解题思路"></a>解题思路</h4><p>首先考虑最后答案长度和给定数字长度一样的情况, 也就是答案的第一位不是进位得到 1 的情况.</p><p>考虑给定数字中第一个不满足相邻两数字之差不等于 $k$ 的位置 $p$, 即 $p$ 满足 $|A_{p - 1} - A_p| = k$, 那么位置 $p$ 在答案中一定是会被修改的, 即使不是 $p$ 也是 $p$ 之前的位置.</p><p>直觉上把位置 $p$ 对应数字加上 1 就好了, 但可能会导致进位或者不满足差的绝对值不等于 $k$ 的限制. 前者可看作修改 $p-1$ 位置上的数字. 对于后者, 枚举位置 $p$ 对于数字的改变量. 如果所有的可能值都不满足限制, 同样可以转为从位置 $p-1$ 下手解决. 确定修改位置 $p$ 后, $p$ 前按照原数字保留, $p$ 后构造满足限制的最小数字就好了.</p><p>至于原数字首位进位的情况, 答案一定是 1 开头的某一个数字, 构造一个尽量小的串就好了.</p><h4 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h4><p><del>一生之敌啊.</del> 不要想一堆似是而非的条件就开始写代码…</p><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// D</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cmath></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstring></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">constexpr</span> <span class="type">int</span> MAXN = <span class="number">1e6</span> + <span class="number">5</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, K;</span><br><span class="line"><span class="type">char</span> str[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> A[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">check</span><span class="params">(<span class="type">int</span> p)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">1</span>; A[p] + k <= <span class="number">9</span>; ++k)</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">abs</span>(A[p] + k - A[p - <span class="number">1</span>]) != K)</span><br><span class="line"> <span class="keyword">return</span> k;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="type">int</span> Ti;</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &Ti);</span><br><span class="line"> <span class="keyword">while</span> (Ti--) {</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%s%d"</span>, str + <span class="number">1</span>, &K);</span><br><span class="line"></span><br><span class="line"> n = <span class="built_in">strlen</span>(str + <span class="number">1</span>);</span><br><span class="line"> A[<span class="number">0</span>] = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) A[i] = str[i] - <span class="string">'0'</span>;</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> p = <span class="number">-1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">2</span>; i <= n && p < <span class="number">0</span>; ++i)</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">abs</span>(A[i - <span class="number">1</span>] - A[i]) == K) p = i;</span><br><span class="line"> <span class="keyword">if</span> (p < <span class="number">0</span>) p = n;</span><br><span class="line"> <span class="keyword">while</span> (p > <span class="number">1</span> && <span class="built_in">check</span>(p) < <span class="number">0</span>)</span><br><span class="line"> --p;</span><br><span class="line"> <span class="type">int</span> d = <span class="built_in">check</span>(p);</span><br><span class="line"> A[p] += (d < <span class="number">0</span> || p == <span class="number">1</span>)? <span class="number">1</span>: d;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = p; i >= <span class="number">1</span>; --i)</span><br><span class="line"> <span class="keyword">if</span> (A[i] > <span class="number">9</span>) A[i - <span class="number">1</span>] += A[i] / <span class="number">10</span>, A[i] %= <span class="number">10</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = (A[<span class="number">0</span>] > <span class="number">0</span>)? <span class="number">1</span>: p + <span class="number">1</span>; i <= n; ++i)</span><br><span class="line"> A[i] = (A[i - <span class="number">1</span>] == K);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = (A[<span class="number">0</span>] == <span class="number">0</span>); i <= n; ++i)</span><br><span class="line"> <span class="built_in">putchar</span>(A[i] + <span class="string">'0'</span>);</span><br><span class="line"> <span class="built_in">putchar</span>(<span class="string">'\n'</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">} </span><br></pre></td></tr></table></figure></div></div><h3 id="E-属性成长-plus"><a href="#E-属性成长-plus" class="headerlink" title="E 属性成长 plus"></a>E 属性成长 plus</h3><h4 id="解题思路-1"><a href="#解题思路-1" class="headerlink" title="解题思路"></a>解题思路</h4><p>注意到和网络赛不一致的地方, 此时按照 $a_i$ 升序排序, 那么 $b_i$ 一定是降序的. 可以证明, 如果选择 $p$ 个 $b$ 属性, 那么选择的 $p$ 个 $b$ 属性的位置一定是排序后位置的一个前缀, $n - p$ 个 $a$ 属性则是后缀. 枚举 $p$ 计算答案就好了, 需要预处理一些量以加速枚举.</p><p>时间复杂度 $O(n \log n)$.</p><p>一个可能的坑点: 最后的答案可能小于 0.</p><h4 id="代码实现-1"><a href="#代码实现-1" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// E</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><climits></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> LL;</span><br><span class="line"><span class="keyword">constexpr</span> <span class="type">int</span> MAXN = <span class="number">2e6</span> + <span class="number">5</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n;</span><br><span class="line"><span class="type">int</span> A[MAXN], B[MAXN], rnk[MAXN];</span><br><span class="line">LL sa[MAXN], sb[MAXN], sia[MAXN], sib[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &n);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i)</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d"</span>, A + i, B + i);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) rnk[i] = i;</span><br><span class="line"> <span class="built_in">sort</span>(rnk + <span class="number">1</span>, rnk + <span class="number">1</span> + n, [](<span class="type">int</span> i, <span class="type">int</span> j) {</span><br><span class="line"> <span class="keyword">return</span> A[i] < A[j] || (A[i] == A[j] && B[i] > B[j]);</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) {</span><br><span class="line"> <span class="type">int</span> b = B[rnk[i]];</span><br><span class="line"> sb[i] = sb[i - <span class="number">1</span>] + b, sib[i] = sib[i - <span class="number">1</span>] + (LL) i * b;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = n; i >= <span class="number">1</span>; --i) {</span><br><span class="line"> <span class="type">int</span> a = A[rnk[i]];</span><br><span class="line"> sa[i] = sa[i + <span class="number">1</span>] + a, sia[i] = sia[i + <span class="number">1</span>] + (LL) i * a;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> LL ans = LLONG_MIN;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> p = <span class="number">0</span>; p <= n; ++p) { <span class="comment">// B: [1, p], A: [p + 1, n]</span></span><br><span class="line"> LL ta = (p + <span class="number">1</span> <= n)? sia[p + <span class="number">1</span>] - p * sa[p + <span class="number">1</span>]: <span class="number">0</span>;</span><br><span class="line"> LL tb = (<span class="number">1</span> <= p)? (p + <span class="number">1</span>) * sb[p] - sib[p]: <span class="number">0</span>;</span><br><span class="line"> ans = <span class="built_in">max</span>(ans, ta + tb - (<span class="number">2LL</span> * p - n) * (<span class="number">2LL</span> * p - n));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%lld\n"</span>, ans);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="F-永久流放"><a href="#F-永久流放" class="headerlink" title="F 永久流放"></a>F 永久流放</h3><h4 id="解题思路-2"><a href="#解题思路-2" class="headerlink" title="解题思路"></a>解题思路</h4><p>记 $f(i, j)$ 表示卡片在第 $j$ 轮传到 $i$ 号玩家时传递次数的期望. 则有</p><script type="math/tex; mode=display">f(i, j) = \sum_{1 \le k \le i - 1} \frac{1}{n-1} \Big( f(k, j) + 1 \Big) + \sum_{i + 1 \le k \le n} \frac{1}{n-1} \Big( f(k, j - 1) + 1 \Big)</script><p>最后的答案就是 $f(n, m)$, 因为第 $m$ 轮结束时卡片只能在 $n$ 号玩家手里, 否则可以继续传递.</p><p>转移利用前缀和优化一下就好了, 时间复杂度 $O(nm)$.</p><h4 id="代码实现-2"><a href="#代码实现-2" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// F</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> LL;</span><br><span class="line"><span class="keyword">constexpr</span> <span class="type">int</span> MAXN = <span class="number">1e3</span> + <span class="number">5</span>, P = <span class="number">998244353</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">fpow</span><span class="params">(<span class="type">int</span> b, <span class="type">int</span> m)</span> </span>{</span><br><span class="line"> <span class="type">int</span> ret = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (m > <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">if</span> (m & <span class="number">1</span>) ret = (LL) ret * b % P;</span><br><span class="line"> b = (LL) b * b % P, m >>= <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, m;</span><br><span class="line"><span class="type">int</span> f[MAXN][MAXN], s[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d"</span>, &n, &m);</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> iv = <span class="built_in">fpow</span>(n - <span class="number">1</span>, P - <span class="number">2</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">1</span>; j <= m; ++j) {</span><br><span class="line"> <span class="type">int</span> s0 = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i)</span><br><span class="line"> s[i] = (s[i - <span class="number">1</span>] + f[i][j - <span class="number">1</span>] + <span class="number">1</span>) % P;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) {</span><br><span class="line"> f[i][j] = (f[i][j] + (LL) iv * s0 % P) % P;</span><br><span class="line"> <span class="keyword">if</span> (i + <span class="number">1</span> <= n)</span><br><span class="line"> f[i][j] = (f[i][j] + (LL) iv * (s[n] - s[i] + P) % P) % P;</span><br><span class="line"> s0 = (s0 + f[i][j] + <span class="number">1</span>) % P;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, f[n][m]);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="G-永世乐土"><a href="#G-永世乐土" class="headerlink" title="G 永世乐土"></a>G 永世乐土</h3><h4 id="解题思路-3"><a href="#解题思路-3" class="headerlink" title="解题思路"></a>解题思路</h4><p>依次考虑答案在二进制下的每一位是否为 1. 当答案某一位是 1 的时候, 能经过位置 $(i, j)$ 的对应值 $A_{i, j}$, 一定有 $A_{i, j}$ 和答案按位与之后和答案相等. 答案某一位是 0 的时候并不影响前面的判断, 所以按照顺序依次确定答案每一位上的值就好了. 此时问题转化为连通性的判定, 接下来怎么做都没问题了.</p><h4 id="代码实现-3"><a href="#代码实现-3" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// G</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> pair<<span class="type">int</span>, <span class="type">int</span>> pii;</span><br><span class="line"><span class="keyword">constexpr</span> <span class="type">int</span> MAXN = <span class="number">1e3</span> + <span class="number">5</span>, MAXM = <span class="number">1e6</span> + <span class="number">5</span>;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> dx[] = { <span class="number">1</span>, <span class="number">0</span> }, dy[] = { <span class="number">0</span>, <span class="number">1</span> };</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, m, s, e, st, ed;</span><br><span class="line"><span class="type">int</span> A[MAXN][MAXN];</span><br><span class="line">pii S[MAXM], E[MAXM];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">idx</span><span class="params">(<span class="type">int</span> x, <span class="type">int</span> y)</span> </span>{ <span class="keyword">return</span> (x - <span class="number">1</span>) * m + y; }</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> DSU {</span><br><span class="line"> <span class="type">int</span> fa[MAXM], size[MAXM];</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">init</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n * m + <span class="number">2</span>; ++i)</span><br><span class="line"> fa[i] = i, size[i] = <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">int</span> <span class="title">findfa</span><span class="params">(<span class="type">int</span> u)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (fa[u] == u)? u: fa[u] = <span class="built_in">findfa</span>(fa[u]);</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">join</span><span class="params">(<span class="type">int</span> u, <span class="type">int</span> v)</span> </span>{</span><br><span class="line"> <span class="type">int</span> fu = <span class="built_in">findfa</span>(u), fv = <span class="built_in">findfa</span>(v);</span><br><span class="line"> <span class="keyword">if</span> (fu == fv) <span class="keyword">return</span>;</span><br><span class="line"> <span class="keyword">if</span> (size[fu] < size[fv]) <span class="built_in">swap</span>(fu, fv);</span><br><span class="line"> fa[fv] = fu, size[fu] += size[fv];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="type">int</span> Ti;</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &Ti);</span><br><span class="line"> <span class="keyword">while</span> (Ti--) {</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d"</span>, &n, &m);</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &s);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= s; ++i)</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d"</span>, &S[i].first, &S[i].second);</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &e);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= e; ++i)</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d"</span>, &E[i].first, &E[i].second);</span><br><span class="line"> <span class="type">int</span> mx = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">1</span>; j <= m; ++j)</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, A[i] + j), mx = <span class="built_in">max</span>(mx, A[i][j]);</span><br><span class="line"></span><br><span class="line"> st = n * m + <span class="number">1</span>, ed = n * m + <span class="number">2</span>;</span><br><span class="line"> <span class="type">int</span> ans = <span class="number">1</span>, k = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> (ans <= mx) ans <<= <span class="number">1</span>, ++k;</span><br><span class="line"> <span class="keyword">while</span> (k >= <span class="number">0</span>) {</span><br><span class="line"> DSU::<span class="built_in">init</span>();</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= s; ++i) {</span><br><span class="line"> <span class="type">int</span> x = S[i].first, y = S[i].second;</span><br><span class="line"> <span class="keyword">if</span> ((A[x][y] & ans) == ans) DSU::<span class="built_in">join</span>(st, <span class="built_in">idx</span>(x, y));</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= e; ++i) {</span><br><span class="line"> <span class="type">int</span> x = E[i].first, y = E[i].second;</span><br><span class="line"> <span class="keyword">if</span> ((A[x][y] & ans) == ans) DSU::<span class="built_in">join</span>(ed, <span class="built_in">idx</span>(x, y));</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> x = <span class="number">1</span>; x <= n; ++x)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> y = <span class="number">1</span>; y <= m; ++y) <span class="keyword">if</span> ((A[x][y] & ans) == ans) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> d = <span class="number">0</span>; d < <span class="number">2</span>; ++d) {</span><br><span class="line"> <span class="type">int</span> nx = x + dx[d], ny = y + dy[d];</span><br><span class="line"> <span class="keyword">if</span> (nx <= n && ny <= m && ((A[nx][ny] & ans) == ans))</span><br><span class="line"> DSU::<span class="built_in">join</span>(<span class="built_in">idx</span>(x, y), <span class="built_in">idx</span>(nx, ny));</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (DSU::<span class="built_in">findfa</span>(st) == DSU::<span class="built_in">findfa</span>(ed)) {</span><br><span class="line"> <span class="keyword">if</span> (--k >= <span class="number">0</span>) ans ^= (<span class="number">1</span> << k);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> ans ^= (<span class="number">1</span> << (k--));</span><br><span class="line"> <span class="keyword">if</span> (k >= <span class="number">0</span>) ans ^= (<span class="number">1</span> << k);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, ans);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="H-朝歌夜雪"><a href="#H-朝歌夜雪" class="headerlink" title="H 朝歌夜雪"></a>H 朝歌夜雪</h3><h4 id="解题思路-4"><a href="#解题思路-4" class="headerlink" title="解题思路"></a>解题思路</h4><p>既然被简化为一维了, 那就按行称呼好了.</p><p>枚举一行中 $n$ 个数的第一个值 $x$, 显然 $x \leq c$, 其余位置均为 $x$ 的约数. 对 $x$ 质因数分解, 记</p><script type="math/tex; mode=display">x = \prod_i{p_i ^ {c_i}}</script><p>针对于每个质数 $p_i$ 单独考虑, 最后只需要把每个质数的贡献乘起来就是 $x$ 对答案的贡献. 对于质数 $p_i$, 贡献为</p><script type="math/tex; mode=display">\sum_{k = 0} ^ {\min\{c_i,\ n - 1\}} \binom{c_i}{k} \binom{n - 1}{k}</script><p>感性理解这个式子的方式很多, 比如说一个高为 $c_i$ 宽为 $n$ 的台阶的可能数量之类的. 计算的时候直接枚举就好了, $c_i$ 大概是 $O(\log c)$ 吧…</p><p>时间复杂度 $O(c\sqrt c)$, $O(\sqrt c)$ 来源于质因数分解.</p><p>至于简化前的情况, 数论忘完了不会做 (</p><h4 id="代码实现-4"><a href="#代码实现-4" class="headerlink" title="代码实现"></a>代码实现</h4><p>滥用 lambda 函数…</p><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// H</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><vector></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> LL;</span><br><span class="line"><span class="type">const</span> LL P = <span class="number">998244353</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="type">int</span> n, C;</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d"</span>, &n, &C);</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> N = <span class="built_in">max</span>(n, C);</span><br><span class="line"> <span class="function">vector<LL> <span class="title">inv</span><span class="params">(N + <span class="number">1</span>)</span>, <span class="title">fac</span><span class="params">(N + <span class="number">1</span>)</span>, <span class="title">ifac</span><span class="params">(N + <span class="number">1</span>)</span></span>;</span><br><span class="line"> inv[<span class="number">1</span>] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">2</span>; i <= N; ++i)</span><br><span class="line"> inv[i] = inv[P % i] * (P - P / i) % P;</span><br><span class="line"> fac[<span class="number">0</span>] = ifac[<span class="number">0</span>] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= N; ++i)</span><br><span class="line"> fac[i] = i * fac[i - <span class="number">1</span>] % P, ifac[i] = inv[i] * ifac[i - <span class="number">1</span>] % P;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">auto</span> binom = [&](<span class="type">int</span> x, <span class="type">int</span> y) {</span><br><span class="line"> <span class="keyword">return</span> fac[x] * ifac[y] % P * ifac[x - y] % P;</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> LL ans = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> x = <span class="number">1</span>; x <= C; ++x) {</span><br><span class="line"> <span class="keyword">auto</span> factor = [](<span class="type">int</span> v) {</span><br><span class="line"> vector<<span class="type">int</span>> ret;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> d = <span class="number">2</span>; d * d <= v; ++d) <span class="keyword">if</span> (v % d == <span class="number">0</span>) {</span><br><span class="line"> ret.<span class="built_in">push_back</span>(<span class="number">0</span>);</span><br><span class="line"> <span class="keyword">while</span> (v % d == <span class="number">0</span>) ++ret.<span class="built_in">back</span>(), v /= d;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (v > <span class="number">1</span>) ret.<span class="built_in">push_back</span>(<span class="number">1</span>);</span><br><span class="line"> <span class="keyword">return</span> ret;</span><br><span class="line"> };</span><br><span class="line"> vector<<span class="type">int</span>> fc = <span class="built_in">factor</span>(x);</span><br><span class="line"> <span class="keyword">auto</span> f = [&](<span class="type">int</span> c) {</span><br><span class="line"> LL ret = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">0</span>; k <= <span class="built_in">min</span>(c, n - <span class="number">1</span>); ++k)</span><br><span class="line"> ret = (ret + <span class="built_in">binom</span>(c, k) * <span class="built_in">binom</span>(n - <span class="number">1</span>, k) % P) % P;</span><br><span class="line"> <span class="keyword">return</span> ret;</span><br><span class="line"> };</span><br><span class="line"> LL t = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">auto</span> c: fc) t = t * <span class="built_in">f</span>(c) % P;</span><br><span class="line"> ans = (ans + t) % P;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%lld\n"</span>, ans);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><hr>]]></content>
<summary type="html"><hr>
<p><strong>题目 &amp; 题面</strong></p>
<ul>
<li><a href="https://acm.xidian.edu.cn/contest.php?cid=1083">https://acm.xidian.edu.cn/contest.php?cid=1083</a></li>
<li><a href="https://acm.xidian.edu.cn/campus/2022/statements.pdf">https://acm.xidian.edu.cn/campus/2022/statements.pdf</a></li>
</ul>
<p>被出题人打爆了.</p></summary>
<category term="题解" scheme="https://depletedprism.github.io/categories/%E9%A2%98%E8%A7%A3/"/>
</entry>
<entry>
<title>Manacher 备忘录</title>
<link href="https://depletedprism.github.io/memos/manacher/"/>
<id>https://depletedprism.github.io/memos/manacher/</id>
<published>2022-03-21T16:00:00.000Z</published>
<updated>2024-12-16T05:34:17.302Z</updated>
<content type="html"><![CDATA[<hr><p>一直记不住的 <del>马拉车</del> 板子. 前几天校内选拔赛还不会写, 惨遭吊打. </p><h2 id="综述"><a href="#综述" class="headerlink" title="综述"></a>综述</h2><p>对于一个长度为 $n$ 的字符串, Manacher 可以在 $O(n)$ 的时间内对每个位置 $i$ 计算一个类似于最长回文半径的东西.</p><p>具体而言, Manacher 在扫描每个位置的时候, 维护一个右端点最靠右的回文串的左右端点, 并借助于这个回文串来计算需要的信息.</p><span id="more"></span><h2 id="回文性质的描述"><a href="#回文性质的描述" class="headerlink" title="回文性质的描述"></a>回文性质的描述</h2><p>记 $d_1(i)$ 表示以位置 $i$ 为中心的长度为奇数的回文串个数, 那么以 $i$ 为中心的最长回文串长度即 $2d_1(i) - 1$.</p><p>记 $d_2(i)$ 表示, 以位置 $i$ 和 $i-1$ 为中心的长度为偶数的回文串个数, 同样可以得到以 $i$ 和 $i-1$ 为中心的最长回文串长度为 $2d_2(i)$. 容易发现 $d_2(1)$ 是没有意义的.</p><h2 id="d-1-与-d-2-的计算"><a href="#d-1-与-d-2-的计算" class="headerlink" title="$d_1$ 与 $d_2$ 的计算"></a>$d_1$ 与 $d_2$ 的计算</h2><p>首先来考虑 $d_1$. 对于一个长度为 $n$ 的字符串 $s$, 枚举每个位置 $i$, 并维护右端点最靠右的回文串的左右端点 $l$ 和 $r$. </p><p>优先考虑 $i < r$ 的情况. 此时对于一个位置 $i$, 可以在维护的这个回文串中得到一个对称的位置 $x$, 对于正整数 $k$, 如果 $s_{x-k}$ 到 $s_{x+k}$ 是回文串, 那么 $s_{i-k}$ 到 $s_{i+k}$ 同样是回文串. </p><script type="math/tex; mode=display">\cdots s_l \cdots \overbrace{s_{x-k} \cdots s_x \cdots s_{x+k}} \cdots \overbrace{s_{i-k} \cdots s_i \cdots s_{i+k}} \cdots s_r \cdots</script><p>由此可以得到</p><script type="math/tex; mode=display">d_1(i) \geq \min\{r - i,\ d_1(x)\}</script><p>容易发现 $x$ 就是 $l + r - i$. 随后需要继续暴力维护 $d_1(i)$ 以保证其正确性. </p><p>对于 $i \geq r$ 的情况, 上面的讨论显然是不能沿用的, 暴力计算就好了. </p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (<span class="type">int</span> l = <span class="number">1</span>, r = <span class="number">0</span>, i = <span class="number">1</span>; i <= n; ++i) {</span><br><span class="line"> <span class="type">int</span> k = (i > r)? <span class="number">1</span>: <span class="built_in">min</span>(r - i, d1[l + r - i]);</span><br><span class="line"> <span class="keyword">while</span> (i - k >= <span class="number">1</span> && i + k <= n && s[i - k] == s[i + k])</span><br><span class="line"> ++k;</span><br><span class="line"> d1[i] = k--;</span><br><span class="line"> <span class="keyword">if</span> (i + k > r)</span><br><span class="line"> l = i - k, r = i + k;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>$d_2$ 的情况类似, 此处直接给出代码实现</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (<span class="type">int</span> l = <span class="number">1</span>, r = <span class="number">0</span>, i = <span class="number">1</span>; i <= n; ++i) {</span><br><span class="line"> <span class="type">int</span> k = (i > r)? <span class="number">0</span>: <span class="built_in">min</span>(r - i + <span class="number">1</span>, d2[l + r - i + <span class="number">1</span>]);</span><br><span class="line"> <span class="keyword">while</span> (i - k - <span class="number">1</span> >= <span class="number">1</span> && i + k <= n && s[i - k - <span class="number">1</span>] == s[i + k])</span><br><span class="line"> ++k;</span><br><span class="line"> d2[i] = k--;</span><br><span class="line"> <span class="keyword">if</span> (i + k > r)</span><br><span class="line"> l = i - k - <span class="number">1</span>, r = i + k;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h2><p>考虑 Manacher 维护的右端点 $r$ 在整个过程中单调不减, 而每次大力计算 $d$ 的过程至少令 $r$ 后移一位, 可以感性认识到时间复杂度为 $O(n)$.</p><h2 id="偶数长度的简化处理"><a href="#偶数长度的简化处理" class="headerlink" title="偶数长度的简化处理"></a>偶数长度的简化处理</h2><p>如果在字符串的每个字符之间都插入一个相同的特殊字符, 就可以把 $d_2$ 的计算转化为 $d_1$ 的情况. 具体而言, 对原来的字符串做这样的变换 <code>abbaab --> #a#b#b#a#a#b#</code>. 此外, 为了简化边界的情况, 往往在前面增加一个更特殊的字符, 即 <code>abbaab --> $#a#b#b#a#a#b#</code>.</p><p>之前一直是这样写 Manacher 的, 优点是实现起来简单, 不过常数也大一点.</p><h2 id="例题"><a href="#例题" class="headerlink" title="例题"></a>例题</h2><h3 id="Luogu-P3805-【模板】manacher-算法"><a href="#Luogu-P3805-【模板】manacher-算法" class="headerlink" title="Luogu P3805 【模板】manacher 算法"></a>Luogu P3805 【模板】manacher 算法</h3><h4 id="题目链接"><a href="#题目链接" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://www.luogu.com.cn/problem/P3805">https://www.luogu.com.cn/problem/P3805</a></li></ul><h4 id="解题思路"><a href="#解题思路" class="headerlink" title="解题思路"></a>解题思路</h4><p>作为 Manacher 的模板题, 自然是不会用 Manacher 写的 (</p><p>首先是经典的求一个字符串中最长回文子串长度, 此时可以对字符串正反做两次哈希然后二分, 时间复杂度 $O(n\log n)$.</p><p>在忘记 Manacher 怎么写的时候很实用.</p><p>事实上存在时间复杂度为 $O(n)$ 的做法, 不过没有单纯用二分直接. 大体上是对每个位置 $i$, 维护位置 $i$ 结尾的最长回文串长度 $R(i)$. 同时 $R(i)$ 存在性质 $R(i)\le R(i - 1) + 2$. 借助与这个性质, 暴力计算 $R(i)$ 的时间复杂度就可以做到 $O(n)$.</p><p>详见 <a href="https://oi-wiki.org/string/hash/#_4">https://oi-wiki.org/string/hash/#_4</a>.</p><p>不过这道题有点卡常, 我写的双模数哈希的 $O(n)$ 做法 TLE 了, 换成自然溢出就过了, 但显然后者是不可取的 (</p><h3 id="Luogu-P4555-国家集训队-最长双回文串"><a href="#Luogu-P4555-国家集训队-最长双回文串" class="headerlink" title="Luogu P4555 [国家集训队]最长双回文串"></a>Luogu P4555 [国家集训队]最长双回文串</h3><h4 id="题目链接-1"><a href="#题目链接-1" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://www.luogu.com.cn/problem/P4555">https://www.luogu.com.cn/problem/P4555</a></li></ul><h4 id="解题思路-1"><a href="#解题思路-1" class="headerlink" title="解题思路"></a>解题思路</h4><p>在最开始的时候提到了一点, Manacher 维护了一个右端点最靠右的回文串.</p><p>记 $f(i)$ 表示以位置 $i$ 结尾的最大回文串长度, $g(i)$ 表示以位置 $i$ 开头的最大回文串长度, 那么所求即</p><script type="math/tex; mode=display">\max_{1\leq i \leq n - 1}\{f(i) + g(i + 1) \}</script><p>$f(i)$ 和 $g(i)$ 可以借助 $d_1$, $d_2$ 计算出来. 时间复杂度 $O(n)$.</p><h4 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h4><p>听说”随手开一大块数组就像随地大小便”, 不管了 (</p><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Luogu P4555</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstring></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">1e5</span> + <span class="number">5</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n;</span><br><span class="line"><span class="type">char</span> str[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> f[MAXN], g[MAXN], d1[MAXN], d2[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">(<span class="type">void</span>)</span> </span>{</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%s"</span>, str + <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"> n = <span class="built_in">strlen</span>(str + <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> l = <span class="number">1</span>, r = <span class="number">0</span>, i = <span class="number">1</span>; i <= n; ++i) {</span><br><span class="line"> <span class="type">int</span> k = (i > r)? <span class="number">1</span>: <span class="built_in">min</span>(r - i, d1[l + r - i]);</span><br><span class="line"> <span class="keyword">while</span> (i - k >= <span class="number">1</span> && i + k <= n && str[i + k] == str[i - k])</span><br><span class="line"> ++k;</span><br><span class="line"> d1[i] = k--;</span><br><span class="line"> <span class="keyword">if</span> (i + k > r)</span><br><span class="line"> l = i - k, r = i + k;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> l = <span class="number">1</span>, r = <span class="number">0</span>, i = <span class="number">1</span>; i <= n; ++i) {</span><br><span class="line"> <span class="type">int</span> k = (i > r)? <span class="number">0</span>: <span class="built_in">min</span>(r - i + <span class="number">1</span>, d2[l + r - i + <span class="number">1</span>]);</span><br><span class="line"> <span class="keyword">while</span> (i - k - <span class="number">1</span> >= <span class="number">1</span> && i + k <= n && str[i - <span class="number">1</span> - k] == str[i + k])</span><br><span class="line"> ++k;</span><br><span class="line"> d2[i] = k--;</span><br><span class="line"> <span class="keyword">if</span> (i + k > r)</span><br><span class="line"> l = i - k - <span class="number">1</span>, r = i + k;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) {</span><br><span class="line"> <span class="keyword">if</span> (i + d1[i] - <span class="number">1</span> <= n)</span><br><span class="line"> f[i + d1[i] - <span class="number">1</span>] = <span class="built_in">max</span>(f[i + d1[i] - <span class="number">1</span>], <span class="number">2</span> * d1[i] - <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">if</span> (i + d2[i] - <span class="number">1</span> <= n)</span><br><span class="line"> f[i + d2[i] - <span class="number">1</span>] = <span class="built_in">max</span>(f[i + d2[i] - <span class="number">1</span>], <span class="number">2</span> * d2[i]);</span><br><span class="line"> <span class="keyword">if</span> (i - d1[i] + <span class="number">1</span> >= <span class="number">1</span>)</span><br><span class="line"> g[i - d1[i] + <span class="number">1</span>] = <span class="built_in">max</span>(g[i - d1[i] + <span class="number">1</span>], <span class="number">2</span> * d1[i] - <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">if</span> (i - d2[i] >= <span class="number">1</span>)</span><br><span class="line"> g[i - d2[i]] = <span class="built_in">max</span>(g[i - d2[i]], <span class="number">2</span> * d2[i]);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = n - <span class="number">1</span>; i >= <span class="number">1</span>; --i)</span><br><span class="line"> f[i] = <span class="built_in">max</span>(f[i], f[i + <span class="number">1</span>] - <span class="number">2</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">2</span>; i <= n; ++i)</span><br><span class="line"> g[i] = <span class="built_in">max</span>(g[i], g[i - <span class="number">1</span>] - <span class="number">2</span>);</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> ans = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n - <span class="number">1</span>; ++i)</span><br><span class="line"> ans = <span class="built_in">max</span>(ans, f[i] + g[i + <span class="number">1</span>]);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, ans);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure></div></div><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>看完 OI-Wiki 的评论之后, 似乎 Manacher 和 Z Algorithm 有千丝万缕的联系.</p><p>事实上两者都维护了一个右端点最靠右的满足某个性质的子串, 然后利用这个子串来计算接下来一个位置对应值. Manacher 维护的是回文串, Z Algorithm 则是一个前缀.</p><p><del>既然新生赛出了个 Z Algorithm, CCCC 校内选拔出了个 Manacher, 那么以后会不会继续出字符串板子呢</del></p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><a href="https://oi-wiki.org/string/manacher/">https://oi-wiki.org/string/manacher/</a></li></ul><hr>]]></content>
<summary type="html"><hr>
<p>一直记不住的 <del>马拉车</del> 板子. 前几天校内选拔赛还不会写, 惨遭吊打. </p>
<h2 id="综述"><a href="#综述" class="headerlink" title="综述"></a>综述</h2><p>对于一个长度为 $n$ 的字符串, Manacher 可以在 $O(n)$ 的时间内对每个位置 $i$ 计算一个类似于最长回文半径的东西.</p>
<p>具体而言, Manacher 在扫描每个位置的时候, 维护一个右端点最靠右的回文串的左右端点, 并借助于这个回文串来计算需要的信息.</p></summary>
<category term="笔记" scheme="https://depletedprism.github.io/categories/%E7%AC%94%E8%AE%B0/"/>
<category term="String" scheme="https://depletedprism.github.io/tags/String/"/>
</entry>
<entry>
<title>我的 2021 年终总结</title>
<link href="https://depletedprism.github.io/logs/2021-summary/"/>
<id>https://depletedprism.github.io/logs/2021-summary/</id>
<published>2022-02-01T03:46:35.000Z</published>
<updated>2024-12-16T05:34:17.302Z</updated>
<content type="html"><![CDATA[<hr><p>连年终总结都拖欠到新年的人是屑 (</p><span id="more"></span><p>但日期不是可以随便改吗.</p><div style="text-align:center;"> <iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=330 height=86 src="//music.163.com/outchain/player?type=2&id=4966649&auto=0&height=66"></iframe></div><p>最初的想法是在元旦写完这个年终总结, 结果当时沉迷 <em>Narcissus</em>, 于是就搁置了. 现在看来, 这篇随笔称作 <em>我的辛丑年年终总结</em> 更加合适和应景一点.</p><p>高三的半年没什么好记录的, 最后能有大学上应该也算是好结局了. 即使这样, 高考之后总归是不满意的, 又没有复读的决心和精力, 那就这样好了. 其实, 就算我高考拿到了于我而言很可观的分数, 也只会是高兴几天, 然后陷入焦虑之中. 或许现在的结果更加适合我.</p><p>看起来很像是安慰自己的观点. 然而确实是这样, 不只是看起来很像.</p><p>原先是计划在暑假稍微做一点竞赛的康复训练, 事实上到开学也没有写掉几个模板. 相比于高一高二的时候除夕还在写代码的自己, 现在我应该没有剩下多少热情和决心了. 暑假大部分的时间还是用来打之前想打的独立游戏了, 绝大多数都是一直没机会玩的老作品. 现在想想, 那时候整天打游戏而不想做其他无论有意义与否的事情, 也有一点报复性的意味.</p><p style="text-align:center"><i>理想的情况是, 这里罗列了我在暑假玩过的游戏, 可惜没有</i></p><p>八月中旬的时候突然想去学一点做独立游戏的技术, 估计是打游戏的副作用. 然后接触了一点点的 OpenGL, 大概学到了渲染正方体表面上的简单光照的程度吧. 表述可能会很奇怪, 毕竟早就不再继续了, 学过的一点知识也忘得差不多了. 如果以后自己真的选择了计算机图形学的方向, 这一段经历和这一段话又可以成为怀念的对象了.</p><p style="text-align:center"><i>如果这里有什么东西可以记录自己学 OpenGL 的经历就好了, 可惜没有</i></p><p>开学. 西电计算机大类的大一上学期的课业安排还是非常宽松的, 我也有其他需要关注的事情. 虽然之前犹豫了一段时间, 但还是计划在大学打打 XCPC. 在高中同其他人吹水, 开玩笑地重复着”不停课还学什么竞赛”的暴论, 但现在恐怕不能够专心只做竞赛一件事了. 所谓”兼顾”者, 可能是我难以具备的能力之一吧.</p><p>新生赛. 无论是网络赛还是现场赛都没有涉及到需要预先学习一些高妙算法的题目. 硬要说的话, 那就排除掉现场赛最后一道 exKMP 好了 (</p><p>在新生赛之前发现了 <a href="https://codeforces.com/blog/entry/92248">Um_nik 的某篇著名博客</a>, 虽然 Um_nik 的观点并不完全适用于 OI, <code>take it too seriously</code> 也没有意思, 但看到这样的观点还是感到警醒.</p><div style="text-align:center;"><img src="/images/2021-summary/Um_nik.jpg" width="206" /> </div><p>新生赛前的一周内稍稍有一点高中打竞赛时的热情, 可惜并没有持续多久. 我以为我可以保持一定的训练强度, 一直坚持到陕西省省赛, 结果省赛因为疫情无限期延后, 原定的 Codeforces 一句话题解计划也没有坚持几天. 简而言之, 摆烂了.</p><p>在最开始, 是因为觉得竞赛有意思才去学竞赛, 现在似乎有一点被竞赛的赛程裹挟着往前的意味了. 总归是本末倒置. 虽然是年终总结, 却越写越发现没什么好总结的, 那就希望新的一年不会再这样好了.</p><p>除去所谓的 Competitive Programming 以外, 还有一个网络科学有关的项目, 当然有队友带着我一起做, 为期一年. 单纯从时间上来看很适合写在明年的年度总结里, 但在现在只是算一个新的开始, 以后再看好了.</p><p>壬寅年快乐!</p><hr>]]></content>
<summary type="html"><hr>
<p>连年终总结都拖欠到新年的人是屑 (</p></summary>
<category term="随笔" scheme="https://depletedprism.github.io/categories/%E9%9A%8F%E7%AC%94/"/>
</entry>
<entry>
<title>一些 Codeforces 简单题的一句话题解 - 壹</title>
<link href="https://depletedprism.github.io/sol/codeforces-short-sol-01/"/>
<id>https://depletedprism.github.io/sol/codeforces-short-sol-01/</id>
<published>2021-12-16T05:19:11.000Z</published>
<updated>2024-12-16T05:34:17.302Z</updated>
<content type="html"><![CDATA[<hr><p>今天的 Codeforces 有在下饭吗?</p><p>是原先在 <a href="https://www.luogu.com.cn/blog/depletedprism/CF-short-sol">洛谷的文章</a> 的精神续作, 直接原因是受 <a href="https://www.bilibili.com/video/BV1NX4y1A7B3">某个学长的视频</a> 的启发.</p><span id="more"></span><p>新的在前头, 老的在后面. 当然只有我写过的 = =</p><p><em>不配打 Div. 1, 有些 Div. 1 的题只是因为出现在了 Div. 2 里, 所以有写.</em></p><h2 id="Edu-Round-132-Div-2"><a href="#Edu-Round-132-Div-2" class="headerlink" title="Edu Round #132 (Div. 2)"></a>Edu Round #132 (Div. 2)</h2><h3 id="F"><a href="#F" class="headerlink" title="F"></a>F</h3><p>首先对题意进行转换. 给定一棵完美 01 Trie, 根结点是源点, 所有叶子是汇点, 需要对所有边赋一个流量限制 $c_i$, 使得最大流恰好为 $f$.</p><p>设 $g_d(x)$ 表示 Trie 上深度为 $d$ 的结点与父亲连边流量为 $x$ 时的方案数, 则有</p><script type="math/tex; mode=display">g_d(x) = (k - x) \sum_{i+j=x}g_{d+1}(i)\cdot g_{d+1}(j) + \sum_{x\leq i+j\le 2k} g_{d+1}(i)\cdot g_{d+1}(j)</script><p>是卷积的形式, NTT 加速计算就好了. 时间复杂度 $O(nk\log k)$.</p><h2 id="Edu-Round-131-Div-2"><a href="#Edu-Round-131-Div-2" class="headerlink" title="Edu Round #131 (Div. 2)"></a>Edu Round #131 (Div. 2)</h2><h3 id="A"><a href="#A" class="headerlink" title="A"></a>A</h3><p>答案只可能是 0, 1 或者 2, 就是样例里的情况.</p><h3 id="B"><a href="#B" class="headerlink" title="B"></a>B</h3><p>$d$ 取 2 的时候答案最优, 按照 $d=2$ 贪心构造排列就好了.</p><h3 id="C"><a href="#C" class="headerlink" title="C"></a>C</h3><p>先假定所有工人都只做对应的任务, 然后调整. 把一项任务从对应的工人转移给另一个人, 就是一人工作时间减 1, 一人工作时间加 2. 反复调整让工作时间最大值最小就好了.</p><h3 id="D"><a href="#D" class="headerlink" title="D"></a>D</h3><p>处理出每个位置可能取值的范围 $\left[\lfloor \frac{i}{b_i + 1} \rfloor + 1, \lfloor \frac{i}{b_i} \rfloor \right]$, 问题转化为给每个区间依次填数, 要求填的数包含在对应区间中且组成一个排列. 从小到大枚举要填的数, 在包含这个数的所有区间中, 显然要先满足右端点小的区间, 取右端点最小的区间填进去就好了.</p><p>注意直接按左右端点为一二关键字排序是错的, WA 了好多发都没反应过来 (</p><h3 id="E"><a href="#E" class="headerlink" title="E"></a>E</h3><p>首先 home 键至多被按一次, 枚举 $s$ 中按 home 键的位置 $i$, 已经利用 $s_{i+1\ldots n}$ 得到了 $t_{j+1\ldots m}$, 这一段只使用 left 和 backspace, 操作数是 $m - j$. 然后按 home 键, 不断按 right, 遇到不匹配的字符就再按一次 backspace, 直到 $s_{1\ldots i}$ 和 $t_{1\ldots j}$ 的最长公共后缀. 记这个后缀长为 $l$, 那么这一部分的操作数是 $(i - j) + (i - l)$.</p><p>最长公共后缀反转 $s$ 和 $t$ 利用 z 函数求出, 时间复杂度 $O(n^2)$.</p><h3 id="F-1"><a href="#F-1" class="headerlink" title="F"></a>F</h3><p>对每个加入的点 $x$ 维护一个 $f(x)$ 表示在区间 $[x + 1, x + d]$ 内点的个数, 那么最后的答案为 $\sum \binom{f(x)}{2}$.</p><p>考虑用线段树维护这个东西. 加入一个点 $x$ 之后需要算 $f(x)$, 维护区间内点的个数就好了. 此外 $x$ 还影响了 $[x-d, x-1]$ 内的 $f$, 打一个加法标记就好了, 具体维护过程可以通过比较 $\sum \binom{f(x)}{2}$ 和 $\sum \binom{f(x) + t}{2}$ 得到, 需要额外维护出 $\sum f(x)$. 删除一个点类似, 所有操作取反就好了.</p><p>时间复杂度 $O(q \log a)$.</p><h2 id="Round-796-Div-2"><a href="#Round-796-Div-2" class="headerlink" title="Round #796 (Div. 2)"></a>Round #796 (Div. 2)</h2><h3 id="A-1"><a href="#A-1" class="headerlink" title="A"></a>A</h3><p>取 $x$ 二进制下最小的那一位. 如果 xor 起来是 0, 就再添上前面一位就好了.</p><h3 id="B-1"><a href="#B-1" class="headerlink" title="B"></a>B</h3><p>如果有奇数, 直接把所有偶数全部合并到奇数上就好了.</p><p>如果没有奇数, 把所有偶数合并, 然后再对得到的和执行 Reduction 操作. 容易发现这样是最优的.</p><h3 id="C-1"><a href="#C-1" class="headerlink" title="C"></a>C</h3><p>十分神秘的一道题.</p><p>在所有的 $t_i$ 和 $s$ 中, 初始的字符出现次数为奇数次, 其余字符出现次数为偶数次, 直接判断就好了.</p><h2 id="Round-796-Div-1"><a href="#Round-796-Div-1" class="headerlink" title="Round #796 (Div. 1)"></a>Round #796 (Div. 1)</h2><h3 id="A-2"><a href="#A-2" class="headerlink" title="A"></a>A</h3><p>先考虑 $k \ge n$ 的情况. 为了尽可能利用每分钟生长的蘑菇和原有的蘑菇, 每个位置都要去到, 且最后的 n 分钟内一定正好采到 n 个位置上的蘑菇. 那么在位置 1 逗留 $k - n$ 分钟, 然后一直采到位置 n 就好了.</p><p>对于 $k < n$ 的情况, 每分钟生长的蘑菇对答案的总贡献是形如 0, 1, …, k - 1 的等差数列, 和开始位置无关. 那么选择一个长度为 k, 其中 $a_i$ 和最大的区间就好了.</p><h3 id="B-2"><a href="#B-2" class="headerlink" title="B"></a>B</h3><p>首先通过 $m$ 次只标记一条边的询问得到每条边的权值 $l_i$, 按边权从小到大的顺序加入边 $i$, 询问加入 $i$ 之后的结果. 如果加入前后相差不等于 $l_i$, 那么加入 $i$ 之后图的连通性不变, $i$ 就不出现在最后的答案中. 这样的询问有 $m-1$ 次, 总共询问 $2m-1$ 次.</p><h3 id="C-2"><a href="#C-2" class="headerlink" title="C"></a>C</h3><p>记 $s_i = \sum_{j = 1}^i a_j - b_j$, 那么对于区间 $[l, r]$, 能操作的条件为 $s_{l-1} = s_r$, 操作后的效果是区间内的所有数都替换为 $s_r$, 同时也是 $s_{l-1}$. 最后的目的是把所有 $s_i$ 都替换成 0.</p><p>直接从 $s_i= 0$ 的位置开始 BFS, 在对应区间上替换 $s_i \neq 0$ 的位置. 可能会重复使用同一个位置, 用 set 记录未覆盖的位置就好了. 时间复杂度 $O(n \log n)$.</p><h2 id="Round-785-Div-2"><a href="#Round-785-Div-2" class="headerlink" title="Round #785 (Div. 2)"></a>Round #785 (Div. 2)</h2><h3 id="A-3"><a href="#A-3" class="headerlink" title="A"></a>A</h3><p>Alice 在 n 为偶数的时候肯定全取走, 在 n 为奇数的时候给 Bob 剩一个最小的. 之后 Bob 就没得选了. 之后计算得分作比较就好了.</p><p>可能要特判 n 为 1 的情况.</p><h3 id="B-3"><a href="#B-3" class="headerlink" title="B"></a>B</h3><p>检查两个相同的字符之间时候是否都出现了 t 中的其余字符就好了.</p><h3 id="C-3"><a href="#C-3" class="headerlink" title="C"></a>C</h3><p>打表发现 n 的范围之内最多有 498 个满足条件的数可以用, 然后就是普通的无穷背包计算方案数的问题了.</p><h3 id="D-1"><a href="#D-1" class="headerlink" title="D"></a>D</h3><p>记 B 中的最小值为 b1, 最大值为 b2, C 中的最小值为 c1, 最大值为 c2. 核心的思路是在 C 的基础上增加一部分元素来得到 A.</p><p>首先要保证 C 中元素全部出现在 B 中, 否则答案一定为 0. 具体而言, 就是保证 c1, c2 都在 B 的范围之内, B 和 C 的公差也能对上. 然后考虑无解的情况, 无解就是 C 往两边无限延伸, 新增的元素也没有和 B 中相同的. 也就是 $c_1 - r < b_1$ 或是 $c_2 + r > b_2$.</p><p>其余情况下, A 的公差一定是 $r$ 的约数, 枚举 $r$ 的约数 $d$, 从 $c_2$ 往后下一个与 B 有重叠的位置就在 $c_2 + \mathrm{lcm}(d, q)$, 显然有 $\mathrm{lcm}(d, q) \leq r$, 但其实是不希望有小于的情况的, 因为此时 $c_1$ 和 $c_2$ 之间 A 和 B 又有除 C 以外的重合. 其余情况对答案就有 ${(\frac{r}{d})}^2$ 的贡献.</p><p>时间复杂度 $O(\sqrt{r} \log r)$. 细节和可能写挂的地方可能有点多… 还是 Think twice, code once 说得有道理.</p><h2 id="Round-781-Div-2"><a href="#Round-781-Div-2" class="headerlink" title="Round #781 (Div. 2)"></a>Round #781 (Div. 2)</h2><h3 id="A-4"><a href="#A-4" class="headerlink" title="A"></a>A</h3><p>构造. 输出 1, n - 3, 1, 1.</p><p><del>system testing 的时候 A FST 一大片, 还好是假的</del></p><h3 id="B-4"><a href="#B-4" class="headerlink" title="B"></a>B</h3><p>模拟. 首先最后数组里的所有数都会是原先出现次数最多的那个数, 一直重复替换其他数值, 然后复制替换后的数组这个过程就好了.</p><h3 id="C-4"><a href="#C-4" class="headerlink" title="C"></a>C</h3><p>首先 spreading 只会发生在某个节点的孩子节点中, 那么 infection 就可以依次选择所有节点的孩子集合, 如果选择完之后还存在没有被感染的节点, 选择未感染节点数最多的孩子集合, 感染一个就好了.</p><h3 id="D-2"><a href="#D-2" class="headerlink" title="D"></a>D</h3><p>看到这个数据范围先猜一个二进制.</p><p>考虑计算 $x \bmod 2^k$ 的值, 这个可以递推得到. 假定已经知道了 $x \bmod 2^{k - 1} = r$, 现在来计算 $x \bmod 2^k$. 考虑 $r$ 的意义, $r$ 就是 $x$ 二进制下前 $k$ 位组成的数, 如果 $x$ 的第 $k + 1$ 位是 1, 那么 $\gcd(x + 2^{k-1} - r, 2^k) = 2^k$, 否则就是 0. 这个 gcd 可以体现为 $\gcd(x + 2^{k-1} - r, x + 2^{k-1} - r + 2^k)$, 然后询问就好了.</p><p>最终的答案就是 $x \bmod 2^{30}$, 总共询问次数就是 30 次.</p><h3 id="E-1"><a href="#E-1" class="headerlink" title="E"></a>E</h3><p>对于小于 $2^k$ 的数, 只需要维护 $a_i$ 前 $k + 1$ 小的位置. 可以利用归纳法证明, 使 $a_i | a_j$ 最小的 $i$ 和 $j$ 一定出现在这 $k + 1$ 个位置中. 用线段树大力维护就好了.</p><p><del>赛时维护了前 2 小的位置, 写着写着发现假了. 官方题解里看到有莫队写法了, 莫队已经走向国际化了 (</del></p><h2 id="Edu-Round-125-Div-2"><a href="#Edu-Round-125-Div-2" class="headerlink" title="Edu Round #125 (Div. 2)"></a>Edu Round #125 (Div. 2)</h2><h3 id="A-5"><a href="#A-5" class="headerlink" title="A"></a>A</h3><p>$O(n^4)$ 暴力 DP.</p><p>进一步思考, 答案不会超过 2. 因为可以先从 $(0, 0)$ 到 $(x, 0)$, 然后再到 $(x, y)$. 此外再额外讨论答案是 0 和是 1 情况就好了.</p><h3 id="B-5"><a href="#B-5" class="headerlink" title="B"></a>B</h3><p>贪心. 能 +x 就加, 不行就 -y.</p><h3 id="C-5"><a href="#C-5" class="headerlink" title="C"></a>C</h3><p>模拟. 括号匹配和回文串判定都是经典问题, 这就是个缝合题 (</p><p>然后就写了个栈又写了个哈希… 其实没有必要, 首先依次枚举每一个字符, 讨论一下遇到的是 <code>(</code> 还是 <code>)</code> 然后计算答案就好了.</p><h3 id="D-3"><a href="#D-3" class="headerlink" title="D"></a>D</h3><p>调和级数复杂度 (枚举倍数) 与二分. 注意读题, 关键在于一次 battle 只能选择一种 unit. 维护一个花费 $c$ 能买到的 unit 的最大 $h_i d_i$, 记作 $g(c)$, 然后用 $g(c)$ 计算预算小于等于 $c$ 时的 $x h_i d_i$ 最大值 $f(c)$, 其中 $x$ 表示 unit 的数量. 时间复杂度可以做到 $O(C \log C + C)$.</p><p>对于每个询问, 在 $f(c)$ 上二分就好了. 总体时间复杂度 $O(n + (C + m)\log C)$.</p><h2 id="Edu-Round-124-Div-2"><a href="#Edu-Round-124-Div-2" class="headerlink" title="Edu Round #124 (Div. 2)"></a>Edu Round #124 (Div. 2)</h2><h3 id="A-6"><a href="#A-6" class="headerlink" title="A"></a>A</h3><p>第一轮之后就只剩奇数了, 所以答案是 $2 ^ n - 1$.</p><h3 id="B-6"><a href="#B-6" class="headerlink" title="B"></a>B</h3><p>假定 $a_i$ 升序, 对于 $i > j$, 反例就是 $2 |a_i - a_j| \geq a_i + a_j$ 即 $a_i \geq 3 a_j$. 所以依次输出 3 的幂就好了.</p><h3 id="C-6"><a href="#C-6" class="headerlink" title="C"></a>C</h3><p>两行中的每个端点向另一行连边就好了, 但是需要分类讨论. 直接讨论具体的连边情况是比较复杂的, 但最后的答案只关心数值, 列出所以情况下最少花费并取最小值就好了.</p><h3 id="D-4"><a href="#D-4" class="headerlink" title="D"></a>D</h3><p>答案只会是给定点上下左右的点, 当然不包括给定的点. 然后建图跑最短路就好了.</p><p>虽然, 事实上只需要从外围向里 BFS 就结束了…</p><h2 id="Round-761-Div-2"><a href="#Round-761-Div-2" class="headerlink" title="Round #761 (Div. 2)"></a>Round #761 (Div. 2)</h2><h3 id="A-7"><a href="#A-7" class="headerlink" title="A"></a>A</h3><p>首先直接对 $S$ 排序, 此时只有 $S$ 中同时存在 <code>a</code>, <code>b</code>, <code>c</code> 且 $T$ 为 <code>"abc"</code> 时 $T$ 对排序后的 $S$ 有影响, 这个时候把所有的 <code>c</code> 放在所有的 <code>b</code> 前面就好了.</p><h3 id="B-7"><a href="#B-7" class="headerlink" title="B"></a>B</h3><p>令 $c = 1$, 然后直接暴力找 $a$, $b$ 就好了.</p><h3 id="C-7"><a href="#C-7" class="headerlink" title="C"></a>C</h3><p>对于一个数 $a_i$, 经过一次操作后可以得到从 $1$ 到 $\lfloor \frac{a_i - 1}{2} \rfloor$ 的任一整数. 然后从小到大构造排列, 如果原先就存在需要的数, 就用原来的, 否则选择一个最小的满足条件的 $a_i$ 进行一次操作.</p><h3 id="D-5"><a href="#D-5" class="headerlink" title="D"></a>D</h3><p>记 $f(i)$ 表示 <code>? i i+1 i+2</code> 得到的结果.</p><p>首先每三个位置分作一组询问, 得到 $f(i), f(i + 3), \cdots$, 由于 $k$ 范围的限制, 一定会存在一个 $i$, 使得 $f(i) \neq f(i+3)$. 然后查询 $f(i + 1)$, $f(i + 2)$. 从 $i$ 到 $i + 5$ 之间一定会有一个位置 $p$, 满足 $f(p) \neq f(p - 1)$ 且 $p$ 和 $p+1$ 一定一个是 imposter, 一个是 crewmate. 此时根据 <code>? p p+1 i</code> 就可以知道 $i$ 的成分, 这样再来 $4$ 次就可以知道从 $i$ 到 $i+5$ 中除去 $p$ 和 $p+1$ 的答案, 额外查询 $1$ 个 <code>? imposter crewmate p</code> 就可以得到 $p$ 和 $p+1$ 的答案.</p><p>对于剩下的 $\frac n3 - 2$ 个三元组, 借助于一个确定的 imposter 和一个确定的 crewmate 并根据 $f(i)$ 的值讨论就好了, 每个三元组用 $2$ 次询问.</p><p>总询问次数是 $n + 3$.</p><h2 id="Edu-Round-118-Div-2"><a href="#Edu-Round-118-Div-2" class="headerlink" title="Edu Round #118 (Div. 2)"></a>Edu Round #118 (Div. 2)</h2><h3 id="A-8"><a href="#A-8" class="headerlink" title="A"></a>A</h3><p>注意读题. 当 $x + y$ 是奇数时无解, 否则给出答案 $(\lfloor \frac x2 \rfloor, \lceil \frac y2 \rceil)$.</p><h3 id="B-8"><a href="#B-8" class="headerlink" title="B"></a>B</h3><p>贪心. 尽可能把较大的数放在左边, 较小的数放在右边. 如果按照该原则无法构造出符合限制的答案, 那么一定无解.</p><h3 id="C-8"><a href="#C-8" class="headerlink" title="C"></a>C</h3><p><del>学二分, 拿红名.</del> 发送出去的表情数量是随行数单调增加的, 直接二分就好了.</p><h3 id="D-6"><a href="#D-6" class="headerlink" title="D"></a>D</h3><p>和求 GCD 思路差不多的一道题. 首先考虑 $a = b$ 的情况, 直接判断 $a$ 和 $x$ 是否相等. 再令 $a < b$, 并记答案为 $f(a, b)$, 枚举一些后继情况之后可以发现</p><script type="math/tex; mode=display">f(a,\ b) = \begin{cases}\text{true} & a \mid b - x \\ \text{false} & b < x\ \text{or}\ a = 0 \\ f(b \bmod a,\ a) & \text{otherwise} \end{cases}</script><h3 id="E-2"><a href="#E-2" class="headerlink" title="E"></a>E</h3><p>对于信息 $j$, 如果学生 $i$ 满足 $m_i = j$, 那么对答案有贡献 $\frac{\min\{ k_i, t \}}{t}$. 注意到一个重要条件 $k_i \leq 20$. 首先考虑 $t > 20$ 的情况, 容易发现该条件下 $t+1$ 时的答案一定小于 $t$ 时的答案. 于是从 $1$ 到 $20$ 枚举 $t$, 对于每一个 $t$ 选择对答案贡献最多的 $t$ 个信息就好了.</p><p>时间复杂度 $O(n + km\log m)$.</p><h2 id="Round-736-Div-2"><a href="#Round-736-Div-2" class="headerlink" title="Round #736 (Div. 2)"></a>Round #736 (Div. 2)</h2><h3 id="A-9"><a href="#A-9" class="headerlink" title="A"></a>A</h3><p>注意到 $P \geq 5$, 那么 $P - 1$ 一定是个偶数, 直接输出 $(P - 1) / 2$ 和 $P - 1$ 就好了.</p><h3 id="B-9"><a href="#B-9" class="headerlink" title="B"></a>B</h3><p>贪心, 让每个棋子的最终位置尽可能往一边靠就好了.</p><h2 id="Round-736-Div-1"><a href="#Round-736-Div-1" class="headerlink" title="Round #736 (Div. 1)"></a>Round #736 (Div. 1)</h2><h3 id="A-10"><a href="#A-10" class="headerlink" title="A"></a>A</h3><p>注意读题, 查询操作并不会改变图的结构, 所以不是模拟, 是分类讨论 = =</p><p>首先, 孤立的点, 以及编号大于所有相邻结点的点一定不会被删去. 其次, 对于一个结点 $u$, 如果存在相邻的点 $v$ 满足 $v > u$, 那么 $u$ 最终一定被删去. 那么对一个结点 $u$ 记录相邻且编号大于 $u$ 的结点个数, 并依此维护答案就好了.</p><p>时间复杂度 $O(m + q)$.</p><h3 id="B-10"><a href="#B-10" class="headerlink" title="B"></a>B</h3><p>记 $d_i = a_i - a_{i - 1}$, 那么 $a_{L\ldots R}$ 是 friends group 的条件就是 $\gcd(d_{L + 1}, \ldots, d_{R}) \geq 2$. 此时二分区间长度, 并维护区间 GCD 就好了. 可以用 ST 表或是线段树来实现.</p><p>如果用 ST 表, 那么时间复杂度为 $O(n \log n)$.</p><hr>]]></content>
<summary type="html"><hr>
<p>今天的 Codeforces 有在下饭吗?</p>
<p>是原先在 <a href="https://www.luogu.com.cn/blog/depletedprism/CF-short-sol">洛谷的文章</a> 的精神续作, 直接原因是受 <a href="https://www.bilibili.com/video/BV1NX4y1A7B3">某个学长的视频</a> 的启发.</p></summary>
<category term="题解" scheme="https://depletedprism.github.io/categories/%E9%A2%98%E8%A7%A3/"/>
</entry>
<entry>
<title>HAOI 2020 退役记</title>
<link href="https://depletedprism.github.io/logs/HAOI-2020/"/>
<id>https://depletedprism.github.io/logs/HAOI-2020/</id>
<published>2020-06-21T10:37:33.000Z</published>
<updated>2024-12-16T05:34:17.302Z</updated>
<content type="html"><![CDATA[<hr><p>这就是, 路的尽头吗.</p><span id="more"></span><h2 id="Day-83"><a href="#Day-83" class="headerlink" title="Day -83"></a>Day -83</h2><div style="text-align:center;"><img src="/images/HAOI-2020/=.png" /> </div><p><em><p style="text-align:center;">图源网络, 进行了简单修改</p></em></p><p>省选未能如期举办, 我的青春结束了.</p><h2 id="Day-1"><a href="#Day-1" class="headerlink" title="Day -1"></a>Day -1</h2><p>回家了.</p><p>网上有场 Codeforces Global Round 8, 然后… 然后我就去睡大觉了 (</p><div style="text-align:center;"><img src="/images/HAOI-2020/shuidajiao001.png" /> </div><p>今年 HA 省队均摊到一个学校至多有两个, 如果能进队那确实是运气因素. 无论是从校内竞争或者是校外, 都没有什么优势.</p><p>当然是不会买 D 类的, 看起来是真的要退役.</p><p>勉强 CSP-S 拿到一等之后, 还是打算去准备省选, 于是又停了课. 再次回到机房那天是 12 月 8 号, <del>为了翘掉学校的 12·8 大合唱</del> 去给高一讲了讲前缀和, 差分, 和树状数组什么的. 无论是高一学弟还是我, 唯一的收获就是明白了我确实没有讲课的天分.</p><p>接着停课直到今天, 也就是 6 月 18 日. 期间准备会考, 补充省选知识点, 做练习, 写往年省选套题, 断断续续的校内模拟赛, Codeforces, 也都成为了过往.</p><p>从一月初考完会考满怀希望回到学校, 逐渐看到 -OH 计划, 看到省选日期不断向后推迟, 看到各高校的招生简章, 大概内心中留存的希望, 也像回学校那天看到的落日, 沉到地平线以下去了.</p><p>学 OI 的初心是什么呢?</p><p>最开始得到 NOIP / NOI 的消息, 是在某个不知名的 C/C++ 教程网站上, 介绍 Dev-cpp 时提到的. 当时还在读初三, 虽然向往但清楚自己参与的希望渺茫. 之后中考结束, 在领取录取通知书时得到了参与 OI 的机会. 当年的 NOI 是本校近几年的最好成绩. 听完竞赛的讲座, 感觉自己在两年后, 也能成为其中一员: 能够学习自己感兴趣的内容, 并证明自己的实力.</p><p>在上初中的时候, 曾经写过一篇文章, 大概是讲自己做事常常没有成绩, 甚至半途而废, 并归咎于自己的专注力和投入不够, 并感到懊悔. 语文老师对此的评价是, 不要以功利化的心态, 太在意事情的结果, 而应该注重于事情的过程.</p><p>在如今充斥竞争的环境之下, 没有个人实力作为基础, 这种心态能立住脚的前提也就是逃避现实吧 (</p><p>此时做出怎样的决策, 也就因人而不同了.</p><h2 id="Day-0"><a href="#Day-0" class="headerlink" title="Day 0"></a>Day 0</h2><p>出去试机, 这次不是河工大了, 环境也好了许多.</p><p>键盘是标准键盘 (我就是在说 <kbd>Backspace</kbd>), 只是 Dev-cpp 在打开 / 新建文件时会 “Runtime ERROR” = = 还是用 MinGW 配合命令行走天下了. 可惜忘了 Windows 键盘映射怎么搞, 想翻以前的博客才发现网线直接被拔了… 又试了试对拍, 感觉还行.</p><p>看了看位置周围都是稳定进队爷, 最后结果可能是我周围一圈人全都进队然后我光荣退役?</p><p>坐在前面的 guyan 突然转向, 让我写个 MTT, LCT 什么的和他对拍, 人听傻了, 和 junble19768 跑路了.</p><p>准考证总算不是一张纸了, 看来可以胸牌退役了 (<del>胸牌作伴好还乡</del></p><h2 id="Day-1-1"><a href="#Day-1-1" class="headerlink" title="Day 1"></a>Day 1</h2><p>考试日.</p><p>看到一堆熟悉的人名, 可惜都不认识. 键盘映射又忘了, 老年选手预定.</p><p>看一眼发现 MinGW 里 gcc 版本比 NOI Linux 里的还老, cmd 又体验极差, 然后又把 Dev-cpp 装上了. (事后才想起来有 Powershell 可以用…</p><p><strong>8sNm5X91Thq=+35y</strong></p><p>开局看到 “组合数问题”, 脊背发凉. 感觉 T1, T2 挺可做, 后来就没有后来了.</p><p>写了写暴力. T2 白给 30 pts, T3 一脸暴力比正解难写的样子. 想了想 T1, 有点慌, 感觉做不出来就没了. 结果胡出来一个 $O(n \log ^ 2 x)$ 的做法, 写半天过了大样例.</p><p>想不出来线性做法, 算了算得分感觉不大行, T1 估计全场 100 pts, 我拿个 60 pts 有锤子用啊 = =</p><p>感觉 T1 标算会应该是线性, 多个 $\log$ 就不管了, 节约时间就没有拍. 中间有去做其他题. T2 感觉能用 Stirling 数把自然数幂干掉, 推了推却没有结果, 感觉是公式记错或者是方向之类的问题. T3 真就一点也不会, 没根据地糊点代码就溜了.</p><p>交完代码之后立刻发现 T2 限制中 $m = 0$ 就是二项式定理, 没时间写了, 又丢 10 pts, 快乐.</p><p>下考场, 不想找教练就直接回家了.</p><p>Day 1 期望得分: 60 + 30 + 0 = 90 pts.</p><p>参照最终结果, 倒不如把花在 T3 的时间用来给 T1 对拍 / 卡常, 或是想想更可做的 T2.</p><p>感觉 HA 的标准分大概在 150 pts 左右? 技不如人甘拜下风. 虽然不大有进省队的希望, 但还是打算给自己的竞赛生涯来个不遗憾的结尾吧.</p><p>本来想 vp 一场 Edu Round 练手, 结果 <del>到家就去做习题集了, 导数真好玩 (</del> 到家就开始颓废了.</p><h2 id="Day-2"><a href="#Day-2" class="headerlink" title="Day 2"></a>Day 2</h2><p>考试日.</p><p>终于默写对键盘映射了. <del>Full Power Mode!</del></p><p><strong>Ybd906-sv?4tbqz2</strong></p><p>开局看题. 看完一遍之后会了 0 + 10 + 30, 感觉要翻盘大概 Day 2 要考 200+ pts?</p><p>看起来 T1 蛮可做的. 又看了一遍题之后发现自己读错题了… 写了个 $O(nm!)$ 的 30 pts 签到. 然后就不会了…</p><p>扫了眼 T2 数据范围, 似乎 $O(n ^ 2)$ 会输的很惨. 想了个 $O(n \log v)$ 逐位考虑的做法, 写出来后发现奥妙重重, 连样例都过不了.</p><p>T3 推了推式子就有 50 pts 了. 大概正解就是 Matrix-Tree 定理之类的东西?</p><p>Day 2 期望得分: 30 + 10 + 50 = 90 pts.</p><p>晚上回学校上晚自习, 去原来的班里找了个空位置就回机房了, 应该是在机房的最后一个晚自习了. <del>所以颓了一晚上</del>.</p><h2 id="Day-3"><a href="#Day-3" class="headerlink" title="Day 3"></a>Day 3</h2><p>回班了, 看周围人准备期末考试.</p><h2 id="Day-4"><a href="#Day-4" class="headerlink" title="Day 4"></a>Day 4</h2><p>晚自习的时候知道了成绩, FST 了 (</p><blockquote><p>不对拍就等于没有写.</p><p>—stdcall</p></blockquote><h2 id="Day-5"><a href="#Day-5" class="headerlink" title="Day 5"></a>Day 5</h2><p>端午放假.</p><p>回去看了看 D1T1 怎么挂的, 改了改结果 AC 了.</p><p>结果 AC 了.</p><p>$O(q \log ^ 2 x)$ AC 了, <del>好像明白自己是怎么退役的了.</del> 仔细算了算, D1T1 拍一下就可以最后一名进队了 (</p><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>学文化课比学 OI 在心态上平稳许多, 没有什么努力一通之后因为各种原因就一无所有的事情发生吧.</p><p><del>暗示自己高考将翻车, 实际上我把所有能决定自己人生轨迹的考试都考砸了 (</del></p><p>可能以后想到自己再无参与国赛的机会, 或者是在其他人问道 “你进省队了吗” 之类问题的时候, 会有一阵无法消去的无力感.</p><p>那才是心之所向啊.</p><hr>]]></content>
<summary type="html"><hr>
<p>这就是, 路的尽头吗.</p></summary>
<category term="随笔" scheme="https://depletedprism.github.io/categories/%E9%9A%8F%E7%AC%94/"/>
</entry>
<entry>
<title>CF321E Ciel and Gondolas 题解</title>
<link href="https://depletedprism.github.io/sol/oj/CF-321E/"/>
<id>https://depletedprism.github.io/sol/oj/CF-321E/</id>
<published>2020-06-15T07:42:44.000Z</published>
<updated>2024-12-16T05:34:17.302Z</updated>
<content type="html"><![CDATA[<hr><h4 id="题目链接"><a href="#题目链接" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://codeforces.com/problemset/problem/321/E">https://codeforces.com/problemset/problem/321/E</a></li><li><del><a href="https://m1.oi-archive.org:9000/problem/?oj=bzoj&pid=5311">https://m1.oi-archive.org:9000/problem/?oj=bzoj&pid=5311</a></del></li></ul><p>同时总结一些 DP 优化的方法.</p><span id="more"></span><h4 id="解题思路"><a href="#解题思路" class="headerlink" title="解题思路"></a>解题思路</h4><ul><li>算法 0: 暴力 DP</li></ul><p>考虑 DP. 设 $f(i, j)$ 表示在前 $i$ 个人中, 选出 $j$ 个队伍的最小花费. 那么有转移</p><script type="math/tex; mode=display">f(i, j) = \min_{j - 1 \le k \le i - 1} \{ f(k, j - 1) + w(k + 1, i) \}</script><p>其中 $w(L, R)$ 表示选择 $[L, R]$ 作为一个队伍的花费, 可用利用二维前缀和在 $O(1)$ 的时间内计算. 具体地, 记 $s(i, j)$ 表示 $u$ 的二维前缀和, 那么 $w$ 可表示为</p><script type="math/tex; mode=display">w(L, R) = \frac{1}{2} \sum_{i = L} ^ R \sum_{j = L} ^ R u_{i, j} = \frac{1}{2} \big( s(R, R) - s(R, L - 1) - s(L - 1, R) + s(L - 1, L - 1) \big)</script><p>此时直接计算的时间复杂度为 $O(n ^ 2 k)$. 还有许多优化的空间.</p><ul><li>算法 1: 四边形不等式优化</li></ul><p>观察上面的转移, 对于一个固定的 $j$, 其余部分转移是 1D1D 的形式. 同时, 代价函数 $w$ 同 $j$ 无关, 且满足四边形不等式, 即</p><script type="math/tex; mode=display">\forall\ l_1 \le l_2 \le r_1 \le r_2,\ w(l_1, r_1) + w(l_2, r_2) \le w(l_1, r_2) + w(l_2, r_1)</script><p>如果交换 $f$ 两维的顺序 (也就是该部分的 $f(i, j)$ 在其他部分为 $f(j, i)$), 得到</p><script type="math/tex; mode=display">f(i, j) = \min_{i \le k \le j} \{ f(i - 1, k - 1) + w(k, j) \}</script><p>枚举 $i$, 每次计算 $f(i, j)$ 时 $f(i - 1, j)$ 的值都已确定, 利用决策单调性分治解决即可, 该部分的具体证明和实现可参考 <a href="https://oi-wiki.org/dp/opt/quadrangle/#1d1d">OI Wiki</a>.</p><p>时间复杂度 $O(nk \log n)$.</p><ul><li>算法 2: 凸优化</li></ul><p>考虑凸优化, 或者称之为 “wqs 二分” / 带权二分.</p><p>如果忽略分作 $k$ 组的限制, 设所分组数为 $x$, 对于每个 $x$, 其最小花费是关于 $x$ 的下凸函数. 证明可参考 <a href="https://www.cnblogs.com/Itst/p/12805678.html">Itst: 浅谈满足四边形不等式的序列划分问题的答案凸性</a>.</p><p>此时二分斜率 $s$, 对于剩下的问题, 设 $f(i)$ 表示前 $i$ 个人中, 任意选择组成队伍的个数时的最小花费. 则有转移</p><script type="math/tex; mode=display">f(i) = \min_{1 < j \le i} \{ f(j - 1) + w(j, i) + s \}</script><p>同时要记录选出队伍组数以在二分时确定改变斜率的范围.</p><p>朴素 DP 的时间复杂度为 $O(n ^ 2 \log w)$, 显得有些鸡肋.</p><p>但内层的 DP 还是可以优化的. 实际上, 在 $i$ 一定时, 代价函数 $w$ 关于 $j$ 单调递增, 体现在 $f(i)$ 关于 $i$ 的图像上即为下凸包.</p><p>此时维护凸包即可. 在枚举 $i$ 的过程中, 在 $i$ 之前的凸包上的点没有意义, 直接删去. 那么利用双端队列维护凸包. 在向凸包中加入一个点时, 需要二分出其加入的位置, 因此要记录凸包中每一条边两端点所在位置.</p><p>维护凸包的操作体现在决策中就是 “决策点会向后更新一段连续的区间”.</p><p>时间复杂度 $O(n \log n \log w)$, 其中 $w$ 表示斜率最大值和最小值之差.</p><h4 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h4><ul><li>算法 0</li></ul><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// CF321E</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cctype></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstring></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> IO {</span><br><span class="line"> <span class="type">const</span> <span class="type">int</span> MAXSIZE = <span class="number">1</span> << <span class="number">18</span> | <span class="number">1</span>;</span><br><span class="line"> <span class="type">char</span> buf[MAXSIZE], *p1, *p2;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">Gc</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> p1 == p2 &&</span><br><span class="line"> (p2 = (p1 = buf) + <span class="built_in">fread</span>(buf, <span class="number">1</span>, MAXSIZE, stdin), p1 == p2)? EOF: *p1++;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">template</span><<span class="keyword">typename</span> T> <span class="keyword">inline</span> <span class="type">void</span> <span class="title">read</span><span class="params">(T& x)</span> </span>{</span><br><span class="line"> x = <span class="number">0</span>; <span class="type">int</span> f = <span class="number">0</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (!<span class="built_in">isdigit</span>(ch)) f |= ch == <span class="string">'-'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">isdigit</span>(ch)) x = x * <span class="number">10</span> + ch - <span class="string">'0'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">if</span> (f) x = -x;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">using</span> IO::read;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">template</span><<span class="keyword">typename</span> T> <span class="keyword">inline</span> <span class="type">bool</span> <span class="title">ckmin</span><span class="params">(T& a, <span class="type">const</span> T& b)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (a > b)? a = b, <span class="literal">true</span>: <span class="literal">false</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">4e3</span> + <span class="number">5</span>, MAXK = <span class="number">8e2</span> + <span class="number">5</span>;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> INF = <span class="number">0x3f3f3f3f</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, K;</span><br><span class="line"><span class="type">int</span> A[MAXN][MAXN];</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> f[MAXN][MAXN];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">w</span><span class="params">(<span class="type">int</span> r1, <span class="type">int</span> c1, <span class="type">int</span> r2, <span class="type">int</span> c2)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (A[r2][c2] - A[r2][c1 - <span class="number">1</span>] - A[r1 - <span class="number">1</span>][c2] + A[r1 - <span class="number">1</span>][c1 - <span class="number">1</span>]) / <span class="number">2</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">w</span><span class="params">(<span class="type">int</span> L, <span class="type">int</span> R)</span> </span>{ <span class="keyword">return</span> <span class="built_in">w</span>(L, L, R, R); }</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="built_in">read</span>(n), <span class="built_in">read</span>(K);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">1</span>; j <= n; ++j)</span><br><span class="line"> <span class="built_in">read</span>(A[i][j]), A[i][j] += A[i - <span class="number">1</span>][j] + A[i][j - <span class="number">1</span>] - A[i - <span class="number">1</span>][j - <span class="number">1</span>];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i <= n; ++i)</span><br><span class="line"> <span class="built_in">memset</span>(f[i], <span class="number">0x3f</span>, (K + <span class="number">1</span>) * <span class="built_in">sizeof</span> (<span class="type">int</span>));</span><br><span class="line"> f[<span class="number">0</span>][<span class="number">0</span>] = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">1</span>; j <= i; ++j)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> k = j - <span class="number">1</span>; k <= i - <span class="number">1</span>; ++k)</span><br><span class="line"> <span class="built_in">ckmin</span>(f[i][j], f[k][j - <span class="number">1</span>] + <span class="built_in">w</span>(k + <span class="number">1</span>, i));</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, f[n][K]);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>算法 1</li></ul><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// CF321E</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cctype></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstring></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> IO {</span><br><span class="line"> <span class="type">const</span> <span class="type">int</span> MAXSIZE = <span class="number">1</span> << <span class="number">18</span> | <span class="number">1</span>;</span><br><span class="line"> <span class="type">char</span> buf[MAXSIZE], *p1, *p2;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">Gc</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> p1 == p2 &&</span><br><span class="line"> (p2 = (p1 = buf) + <span class="built_in">fread</span>(buf, <span class="number">1</span>, MAXSIZE, stdin), p1 == p2)? EOF: *p1++;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">template</span><<span class="keyword">typename</span> T> <span class="keyword">inline</span> <span class="type">void</span> <span class="title">read</span><span class="params">(T& x)</span> </span>{</span><br><span class="line"> x = <span class="number">0</span>; <span class="type">int</span> f = <span class="number">0</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (!<span class="built_in">isdigit</span>(ch)) f |= ch == <span class="string">'-'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">isdigit</span>(ch)) x = x * <span class="number">10</span> + ch - <span class="string">'0'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">if</span> (f) x = -x;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">using</span> IO::read;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">template</span><<span class="keyword">typename</span> T> <span class="keyword">inline</span> <span class="type">bool</span> <span class="title">ckmin</span><span class="params">(T& a, <span class="type">const</span> T& b)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (a > b)? a = b, <span class="literal">true</span>: <span class="literal">false</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">4e3</span> + <span class="number">5</span>, MAXK = <span class="number">8e2</span> + <span class="number">5</span>;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> INF = <span class="number">0x3f3f3f3f</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, K;</span><br><span class="line"><span class="type">int</span> A[MAXN][MAXN];</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> f[MAXN][MAXN];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">w</span><span class="params">(<span class="type">int</span> r1, <span class="type">int</span> c1, <span class="type">int</span> r2, <span class="type">int</span> c2)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> A[r2][c2] - A[r2][c1 - <span class="number">1</span>] - A[r1 - <span class="number">1</span>][c2] + A[r1 - <span class="number">1</span>][c1 - <span class="number">1</span>];</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">w</span><span class="params">(<span class="type">int</span> L, <span class="type">int</span> R)</span> </span>{ <span class="keyword">return</span> <span class="built_in">w</span>(L, L, R, R) / <span class="number">2</span>; }</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">solve</span><span class="params">(<span class="type">int</span>* h, <span class="type">const</span> <span class="type">int</span>* g, <span class="type">int</span> L, <span class="type">int</span> R, <span class="type">int</span> kl, <span class="type">int</span> kr)</span> </span>{</span><br><span class="line"> <span class="type">int</span> Mid = (L + R) / <span class="number">2</span>, k = kl;</span><br><span class="line"> h[Mid] = g[k - <span class="number">1</span>] + <span class="built_in">w</span>(k, Mid);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = kl + <span class="number">1</span>; i <= <span class="built_in">min</span>(kr, Mid); ++i)</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">ckmin</span>(h[Mid], g[i - <span class="number">1</span>] + <span class="built_in">w</span>(i, Mid))) k = i;</span><br><span class="line"> <span class="keyword">if</span> (L < Mid) <span class="built_in">solve</span>(h, g, L, Mid - <span class="number">1</span>, kl, k);</span><br><span class="line"> <span class="keyword">if</span> (R > Mid) <span class="built_in">solve</span>(h, g, Mid + <span class="number">1</span>, R, k, kr);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="built_in">read</span>(n), <span class="built_in">read</span>(K);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">1</span>; j <= n; ++j)</span><br><span class="line"> <span class="built_in">read</span>(A[i][j]), A[i][j] += A[i - <span class="number">1</span>][j] + A[i][j - <span class="number">1</span>] - A[i - <span class="number">1</span>][j - <span class="number">1</span>];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i <= K; ++i)</span><br><span class="line"> <span class="built_in">memset</span>(f[i], <span class="number">0x3f</span>, (n + <span class="number">1</span>) * <span class="built_in">sizeof</span> (<span class="type">int</span>));</span><br><span class="line"> f[<span class="number">0</span>][<span class="number">0</span>] = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= K; ++i)</span><br><span class="line"> <span class="built_in">solve</span>(f[i], f[i - <span class="number">1</span>], <span class="number">1</span>, n, <span class="number">1</span>, n);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, f[K][n]);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>算法 2</li></ul><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// CF321E</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cctype></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cassert></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstring></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> IO {</span><br><span class="line"> <span class="type">const</span> <span class="type">int</span> MAXSIZE = <span class="number">1</span> << <span class="number">18</span> | <span class="number">1</span>;</span><br><span class="line"> <span class="type">char</span> buf[MAXSIZE], *p1, *p2;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">Gc</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> p1 == p2 &&</span><br><span class="line"> (p2 = (p1 = buf) + <span class="built_in">fread</span>(buf, <span class="number">1</span>, MAXSIZE, stdin), p1 == p2)? EOF: *p1++;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">template</span><<span class="keyword">typename</span> T> <span class="keyword">inline</span> <span class="type">void</span> <span class="title">read</span><span class="params">(T& x)</span> </span>{</span><br><span class="line"> x = <span class="number">0</span>; <span class="type">int</span> f = <span class="number">0</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (!<span class="built_in">isdigit</span>(ch)) f |= ch == <span class="string">'-'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">isdigit</span>(ch)) x = x * <span class="number">10</span> + ch - <span class="string">'0'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">if</span> (f) x = -x;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">using</span> IO::read;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">template</span><<span class="keyword">typename</span> T> <span class="keyword">inline</span> <span class="type">bool</span> <span class="title">ckmin</span><span class="params">(T& a, <span class="type">const</span> T& b)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (b < a)? a = b, <span class="literal">true</span>: <span class="literal">false</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">4e3</span> + <span class="number">5</span>, MAXK = <span class="number">8e2</span> + <span class="number">5</span>;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> INF = <span class="number">0x3f3f3f3f</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, K;</span><br><span class="line"><span class="type">int</span> A[MAXN][MAXN];</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Item</span> {</span><br><span class="line"> <span class="type">int</span> v, c;</span><br><span class="line"> <span class="built_in">Item</span>() { v = c = <span class="number">0</span>; }</span><br><span class="line"> <span class="built_in">Item</span>(<span class="type">int</span> _v, <span class="type">int</span> _c): <span class="built_in">v</span>(_v), <span class="built_in">c</span>(_c) { }</span><br><span class="line"> Item <span class="keyword">operator</span> + (<span class="type">const</span> Item& rhs) <span class="type">const</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Item</span>(v + rhs.v, c + rhs.c);</span><br><span class="line"> }</span><br><span class="line"> <span class="type">bool</span> <span class="keyword">operator</span> < (<span class="type">const</span> Item& rhs) <span class="type">const</span> {</span><br><span class="line"> <span class="keyword">return</span> v < rhs.v || (v == rhs.v && c < rhs.c);</span><br><span class="line"> }</span><br><span class="line"> <span class="type">bool</span> <span class="keyword">operator</span> <= (<span class="type">const</span> Item& rhs) <span class="type">const</span> {</span><br><span class="line"> <span class="keyword">return</span> !(rhs < *<span class="keyword">this</span>);</span><br><span class="line"> }</span><br><span class="line">} f[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Que</span> {</span><br><span class="line"> <span class="type">int</span> p, L, R;</span><br><span class="line"> <span class="built_in">Que</span>() { p = L = R = <span class="number">0</span>; }</span><br><span class="line"> <span class="built_in">Que</span>(<span class="type">int</span> _p, <span class="type">int</span> _L, <span class="type">int</span> _R): <span class="built_in">p</span>(_p), <span class="built_in">L</span>(_L), <span class="built_in">R</span>(_R) { }</span><br><span class="line">} Q[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> Item <span class="title">F</span><span class="params">(<span class="type">int</span> j, <span class="type">int</span> i)</span> </span>{ <span class="comment">// 1 <= j < i</span></span><br><span class="line"> <span class="keyword">return</span> f[j] + <span class="built_in">Item</span>((A[i][i] + A[j][j] - <span class="number">2</span> * A[i][j]) / <span class="number">2</span>, <span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">solve</span><span class="params">(<span class="type">const</span> <span class="type">int</span>& s)</span> </span>{</span><br><span class="line"> <span class="type">int</span> head = <span class="number">1</span>, tail = <span class="number">0</span>;</span><br><span class="line"> Q[++tail] = <span class="built_in">Que</span>(<span class="number">0</span>, <span class="number">1</span>, n), f[<span class="number">0</span>] = <span class="built_in">Item</span>(<span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) {</span><br><span class="line"> <span class="keyword">while</span> (head <= tail && Q[head].R < i) ++head;</span><br><span class="line"> <span class="type">int</span> p = Q[head].p;</span><br><span class="line"> Q[head].L = i, f[i] = <span class="built_in">Item</span>(<span class="built_in">F</span>(p, i).v + s, f[p].c + <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">if</span> (head > tail)</span><br><span class="line"> Q[++tail] = <span class="built_in">Que</span>(i, <span class="number">1</span>, n);</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (<span class="built_in">F</span>(i, n) <= <span class="built_in">F</span>(p, n)) {</span><br><span class="line"> <span class="keyword">while</span> (head <= tail && <span class="built_in">F</span>(i, Q[tail].L) <= <span class="built_in">F</span>(Q[tail].p, Q[tail].L))</span><br><span class="line"> --tail;</span><br><span class="line"> <span class="type">int</span> L = Q[tail].L, R = Q[tail].R; p = <span class="number">-1</span>;</span><br><span class="line"> <span class="keyword">while</span> (L <= R) {</span><br><span class="line"> <span class="type">int</span> Mid = (L + R) / <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">F</span>(i, Mid) <= <span class="built_in">F</span>(Q[tail].p, Mid)) R = Mid - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">else</span> L = Mid + <span class="number">1</span>, p = Mid;</span><br><span class="line"> }</span><br><span class="line"> Q[tail].R = p;</span><br><span class="line"> <span class="keyword">if</span> (p + <span class="number">1</span> <= n) Q[++tail] = <span class="built_in">Que</span>(i, p + <span class="number">1</span>, n);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> f[n].c;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">assert</span>(<span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin));</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="built_in">read</span>(n), <span class="built_in">read</span>(K);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">1</span>; j <= n; ++j)</span><br><span class="line"> <span class="built_in">read</span>(A[i][j]), A[i][j] += A[i - <span class="number">1</span>][j] + A[i][j - <span class="number">1</span>] - A[i - <span class="number">1</span>][j - <span class="number">1</span>];</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> L = <span class="number">0</span>, R = A[n][n], ans = <span class="number">-1</span>;</span><br><span class="line"> <span class="keyword">while</span> (L <= R) {</span><br><span class="line"> <span class="type">int</span> Mid = (L + R) / <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">solve</span>(Mid) <= K)</span><br><span class="line"> ans = f[n].v - K * Mid, R = Mid - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">else</span> L = Mid + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, ans);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h4><ul><li>OI Wiki, <a href="https://oi-wiki.org/dp/opt/quadrangle/">四边形不等式优化</a>.</li><li>Itst, <a href="https://www.cnblogs.com/Itst/p/12805678.html">浅谈满足四边形不等式的序列划分问题的答案凸性</a></li><li>T_Y_P_E, <a href="https://www.cnblogs.com/T-Y-P-E/p/10217028.html#%E4%BB%A3%E7%A0%81">【Codeforces 321E / BZOJ 5311】【DP凸优化】【单调队列】贞鱼</a>.</li></ul><hr>]]></content>
<summary type="html"><hr>
<h4 id="题目链接"><a href="#题目链接" class="headerlink" title="题目链接"></a>题目链接</h4><ul>
<li><a href="https://codeforces.com/problemset/problem/321/E">https://codeforces.com/problemset/problem/321/E</a></li>
<li><del><a href="https://m1.oi-archive.org:9000/problem/?oj=bzoj&amp;pid=5311">https://m1.oi-archive.org:9000/problem/?oj=bzoj&amp;pid=5311</a></del></li>
</ul>
<p>同时总结一些 DP 优化的方法.</p></summary>
<category term="题解" scheme="https://depletedprism.github.io/categories/%E9%A2%98%E8%A7%A3/"/>
<category term="DP" scheme="https://depletedprism.github.io/tags/DP/"/>
</entry>
<entry>
<title>一些简单的模拟费用流问题</title>
<link href="https://depletedprism.github.io/memos/simulated-flow/"/>
<id>https://depletedprism.github.io/memos/simulated-flow/</id>
<published>2020-06-06T05:28:55.000Z</published>
<updated>2024-12-16T05:34:17.302Z</updated>
<content type="html"><![CDATA[<hr><p>祝贺我又学了一个学不明白的东西 (</p><h2 id="综述"><a href="#综述" class="headerlink" title="综述"></a>综述</h2><p>模拟费用流, 大概是利用流的一些性质, 从而用数据结构高效模拟费用流.</p><p>基础理论和模型可以看看文末的参考资料, 这里只是记录我做过的一些题目.</p><span id="more"></span><h2 id="例题"><a href="#例题" class="headerlink" title="例题"></a>例题</h2><p>题目顺序随心情.</p><hr><p>首先是一些 “模拟” 费用流的例子.</p><h3 id="CF280D-k-Maximum-Subsequence-Sum"><a href="#CF280D-k-Maximum-Subsequence-Sum" class="headerlink" title="CF280D k-Maximum Subsequence Sum"></a>CF280D k-Maximum Subsequence Sum</h3><h4 id="题目链接"><a href="#题目链接" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://codeforces.com/problemset/problem/280/D">https://codeforces.com/problemset/problem/280/D</a></li></ul><h4 id="解题思路"><a href="#解题思路" class="headerlink" title="解题思路"></a>解题思路</h4><p>首先有一个费用流做法. 设源汇点 $S$, $T$, 同时将每个位置拆为入点 $i$ 和出点 $i’$.</p><ol><li>连边 $(S, S’)$, 容量为 $k$, 费用为 $0$.</li><li>连边 $(S’, i)$, 容量为 $1$, 费用为 $0$.</li><li>连边 $(i, i’)$, 容量为 $1$, 费用为 $a_i$.</li><li>连边 $(i’, i + 1)$, 容量为 $1$, 费用为 $0$.</li><li>连边 $(i’, T)$, 容量为 $1$, 费用为 $0$.</li></ol><p>此时将费用取反, 求最小费用流即可. 可惜时间复杂度不够优秀.</p><p>注意到每次增广的过程, 本质上是选择序列一段区间中的最大连续子段和, 直接用线段树维护即可.</p><p>同时需要维护反向边, 也就是将该区间翻转并将权值取反. 那么记录子段和时需记录该子段对应区间端点, 以及最小子段和, 用于权值取反后快速计算现有区间最大子段和. 这样区间取反可打标记维护.</p><p>根据这个思路, 单点修改就没什么意思了. 注意每组询问直接独立, 在区间取反后需要撤销影响.</p><p>时间复杂度 $O(n \log n)$.</p><h4 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// CF280D</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cctype></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> IO {</span><br><span class="line"> <span class="type">const</span> <span class="type">int</span> MAXSIZE = <span class="number">1</span> << <span class="number">18</span> | <span class="number">1</span>;</span><br><span class="line"> <span class="type">char</span> buf[MAXSIZE], *p1, *p2;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">Gc</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> p1 == p2 &&</span><br><span class="line"> (p2 = (p1 = buf) + <span class="built_in">fread</span>(buf, <span class="number">1</span>, MAXSIZE, stdin), p1 == p2)? EOF: *p1++;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">template</span><<span class="keyword">typename</span> T> <span class="keyword">inline</span> <span class="type">void</span> <span class="title">read</span><span class="params">(T& x)</span> </span>{</span><br><span class="line"> x = <span class="number">0</span>; <span class="type">int</span> f = <span class="number">0</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (!<span class="built_in">isdigit</span>(ch)) f |= ch == <span class="string">'-'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">isdigit</span>(ch)) x = x * <span class="number">10</span> + ch - <span class="string">'0'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">if</span> (f) x = -x;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">using</span> IO::read;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">1e5</span> + <span class="number">5</span>, MAXM = MAXN << <span class="number">2</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, q, top;</span><br><span class="line"><span class="type">int</span> A[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Item</span> {</span><br><span class="line"> <span class="type">int</span> L, R, v;</span><br><span class="line"> <span class="built_in">Item</span>() { L = MAXN, R = -MAXN, v = <span class="number">0</span>; }</span><br><span class="line"> <span class="built_in">Item</span>(<span class="type">int</span> _L, <span class="type">int</span> _R, <span class="type">int</span> _v): <span class="built_in">L</span>(_L), <span class="built_in">R</span>(_R), <span class="built_in">v</span>(_v) { }</span><br><span class="line"> Item <span class="keyword">operator</span> + (<span class="type">const</span> Item& rhs) <span class="type">const</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Item</span>(<span class="built_in">min</span>(L, rhs.L), <span class="built_in">max</span>(R, rhs.R), v + rhs.v);</span><br><span class="line"> }</span><br><span class="line"> <span class="type">bool</span> <span class="keyword">operator</span> < (<span class="type">const</span> Item& rhs) <span class="type">const</span> {</span><br><span class="line"> <span class="keyword">return</span> v < rhs.v;</span><br><span class="line"> }</span><br><span class="line">} stk[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> lc (nd << 1)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> rc (nd << 1 | 1)</span></span><br><span class="line"><span class="keyword">namespace</span> SGT {</span><br><span class="line"> <span class="keyword">struct</span> <span class="title class_">Node</span> {</span><br><span class="line"> Item s, MxL, MxR, MxM, MnL, MnR, MnM;</span><br><span class="line"> <span class="built_in">Node</span>() { }</span><br><span class="line"> <span class="built_in">Node</span>(Item v) { s = MxL = MxR = MxM = MnL = MnR = MnM = v; }</span><br><span class="line"> Node <span class="keyword">operator</span> + (<span class="type">const</span> Node& rhs) <span class="type">const</span> {</span><br><span class="line"> Node ret;</span><br><span class="line"> ret.s = s + rhs.s;</span><br><span class="line"></span><br><span class="line"> ret.MxL = <span class="built_in">max</span>(MxL, s + rhs.MxL);</span><br><span class="line"> ret.MxR = <span class="built_in">max</span>(rhs.MxR, rhs.s + MxR);</span><br><span class="line"> ret.MxM = <span class="built_in">max</span>(MxR + rhs.MxL, <span class="built_in">max</span>(MxM, rhs.MxM));</span><br><span class="line"></span><br><span class="line"> ret.MnL = <span class="built_in">min</span>(MnL, s + rhs.MnL);</span><br><span class="line"> ret.MnR = <span class="built_in">min</span>(rhs.MnR, rhs.s + MnR);</span><br><span class="line"> ret.MnM = <span class="built_in">min</span>(MnR + rhs.MnL, <span class="built_in">min</span>(MnM, rhs.MnM));</span><br><span class="line"> <span class="keyword">return</span> ret;</span><br><span class="line"> }</span><br><span class="line"> } dat[MAXM];</span><br><span class="line"> <span class="type">bool</span> res[MAXM];</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">maintain</span><span class="params">(<span class="type">int</span> nd)</span> </span>{ dat[nd] = dat[lc] + dat[rc]; }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">push</span><span class="params">(<span class="type">int</span> nd)</span> </span>{</span><br><span class="line"> <span class="built_in">swap</span>(dat[nd].MxM, dat[nd].MnM);</span><br><span class="line"> <span class="built_in">swap</span>(dat[nd].MxL, dat[nd].MnL), <span class="built_in">swap</span>(dat[nd].MxR, dat[nd].MnR);</span><br><span class="line"> dat[nd].s.v *= <span class="number">-1</span>;</span><br><span class="line"> dat[nd].MxL.v *= <span class="number">-1</span>, dat[nd].MxR.v *= <span class="number">-1</span>, dat[nd].MxM.v *= <span class="number">-1</span>;</span><br><span class="line"> dat[nd].MnL.v *= <span class="number">-1</span>, dat[nd].MnR.v *= <span class="number">-1</span>, dat[nd].MnM.v *= <span class="number">-1</span>;</span><br><span class="line"> res[nd] ^= <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">pushdown</span><span class="params">(<span class="type">int</span> nd)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (res[nd]) <span class="built_in">push</span>(lc), <span class="built_in">push</span>(rc), res[nd] = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">build</span><span class="params">(<span class="type">int</span> nd, <span class="type">int</span> L, <span class="type">int</span> R)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (L == R)</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">void</span>( dat[nd] = <span class="built_in">Item</span>(L, R, A[L]) );</span><br><span class="line"> <span class="type">int</span> Mid = (L + R) / <span class="number">2</span>;</span><br><span class="line"> <span class="built_in">build</span>(lc, L, Mid), <span class="built_in">build</span>(rc, Mid + <span class="number">1</span>, R);</span><br><span class="line"> <span class="built_in">maintain</span>(nd);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">Rev</span><span class="params">(<span class="type">int</span> nd, <span class="type">int</span> L, <span class="type">int</span> R, <span class="type">const</span> <span class="type">int</span>& opL, <span class="type">const</span> <span class="type">int</span>& opR)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (opL <= L && R <= opR) <span class="keyword">return</span> <span class="built_in">push</span>(nd);</span><br><span class="line"> <span class="type">int</span> Mid = (L + R) / <span class="number">2</span>;</span><br><span class="line"> <span class="built_in">pushdown</span>(nd);</span><br><span class="line"> <span class="keyword">if</span> (opL <= Mid) <span class="built_in">Rev</span>(lc, L, Mid, opL, opR);</span><br><span class="line"> <span class="keyword">if</span> (opR > Mid) <span class="built_in">Rev</span>(rc, Mid + <span class="number">1</span>, R, opL, opR);</span><br><span class="line"> <span class="built_in">maintain</span>(nd);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">Mdy</span><span class="params">(<span class="type">int</span> nd, <span class="type">int</span> L, <span class="type">int</span> R, <span class="type">const</span> <span class="type">int</span>& p, <span class="type">const</span> <span class="type">int</span>& v)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (L == R)</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">void</span>( dat[nd] = <span class="built_in">Item</span>(L, R, v) );</span><br><span class="line"> <span class="built_in">pushdown</span>(nd);</span><br><span class="line"> <span class="type">int</span> Mid = (L + R) / <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">if</span> (p <= Mid) <span class="built_in">Mdy</span>(lc, L, Mid, p, v); <span class="keyword">else</span> <span class="built_in">Mdy</span>(rc, Mid + <span class="number">1</span>, R, p, v);</span><br><span class="line"> <span class="built_in">maintain</span>(nd);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function">Node <span class="title">Qry</span><span class="params">(<span class="type">int</span> nd, <span class="type">int</span> L, <span class="type">int</span> R, <span class="type">const</span> <span class="type">int</span>& opL, <span class="type">const</span> <span class="type">int</span>& opR)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (opL <= L && R <= opR) <span class="keyword">return</span> dat[nd];</span><br><span class="line"> <span class="type">int</span> Mid = (L + R) / <span class="number">2</span>;</span><br><span class="line"> <span class="built_in">pushdown</span>(nd);</span><br><span class="line"> <span class="keyword">if</span> (opR <= Mid) <span class="keyword">return</span> <span class="built_in">Qry</span>(lc, L, Mid, opL, opR);</span><br><span class="line"> <span class="keyword">if</span> (opL > Mid) <span class="keyword">return</span> <span class="built_in">Qry</span>(rc, Mid + <span class="number">1</span>, R, opL, opR);</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Qry</span>(lc, L, Mid, opL, opR) + <span class="built_in">Qry</span>(rc, Mid + <span class="number">1</span>, R, opL, opR);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="meta">#<span class="keyword">undef</span> lc</span></span><br><span class="line"><span class="meta">#<span class="keyword">undef</span> rc</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="built_in">read</span>(n);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) <span class="built_in">read</span>(A[i]);</span><br><span class="line"></span><br><span class="line"> SGT::<span class="built_in">build</span>(<span class="number">1</span>, <span class="number">1</span>, n);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">read</span>(q);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> opt, L, R, k, ans; q; --q) {</span><br><span class="line"> <span class="built_in">read</span>(opt), <span class="built_in">read</span>(L);</span><br><span class="line"> <span class="keyword">switch</span> (opt) {</span><br><span class="line"> <span class="keyword">case</span> <span class="number">0</span>:</span><br><span class="line"> <span class="built_in">read</span>(k), SGT::<span class="built_in">Mdy</span>(<span class="number">1</span>, <span class="number">1</span>, n, L, k);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line"> <span class="built_in">read</span>(R), <span class="built_in">read</span>(k), ans = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> (k--) {</span><br><span class="line"> Item v = SGT::<span class="built_in">Qry</span>(<span class="number">1</span>, <span class="number">1</span>, n, L, R).MxM;</span><br><span class="line"> <span class="keyword">if</span> (v.v <= <span class="number">0</span>) <span class="keyword">break</span>;</span><br><span class="line"> ans += v.v, SGT::<span class="built_in">Rev</span>(<span class="number">1</span>, <span class="number">1</span>, n, v.L, v.R), stk[++top] = v;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">while</span> (top > <span class="number">0</span>) {</span><br><span class="line"> Item v = stk[top--];</span><br><span class="line"> SGT::<span class="built_in">Rev</span>(<span class="number">1</span>, <span class="number">1</span>, n, v.L, v.R);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, ans);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">default</span>: <span class="built_in">fprintf</span>(stderr, <span class="string">"ERR\n"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="Luogu-P6122「NEERC2016」Mole-Tunnels"><a href="#Luogu-P6122「NEERC2016」Mole-Tunnels" class="headerlink" title="Luogu P6122「NEERC2016」Mole Tunnels"></a>Luogu P6122「NEERC2016」Mole Tunnels</h3><h4 id="题目链接-1"><a href="#题目链接-1" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://www.luogu.com.cn/problem/P6122">https://www.luogu.com.cn/problem/P6122</a></li></ul><h4 id="解题思路-1"><a href="#解题思路-1" class="headerlink" title="解题思路"></a>解题思路</h4><p>首先有一个费用流思路. 设源汇点分别为 $S$, $T$, 将每只鼹鼠视作流量.</p><ol><li>对于树上每条边, 连边 $(u, \lfloor \frac{u}{2} \rfloor)$, $(\lfloor \frac{u}{2} \rfloor, u)$, 容量为 $\infty$, 费用为 $1$.</li><li>对于树上每个点 $u$, 连边 $(u, T)$, 容量为 $c_u$, 费用为 $0$.</li><li>对于每只鼹鼠, 依次向其树上所在位置 $u$ 连边 $(S, u)$, 容量为 $1$, 费用为 $0$.</li></ol><p>观察每次增广的过程, 都是选择树上一条路径, 为保证费用尽量小, 显然是在要求路径尽量短.</p><p>考虑到题中给定树为二叉树, 其深度为 $O(\log n)$. 枚举新增鼹鼠位置 $s$ 和最终匹配位置的 LCA $t$. 同时对每个节点 $u$ 记录位置 $p(u)$, 表示 $u$ 子树内同 $u$ 匹配的最优位置.</p><p>此时增广的路径即 $s \rightarrow t \rightarrow {p}(t)$, 更新流量计算费用即可.</p><p>${p}(u)$ 可从下向上递推计算. 另外需记录树边中的流量. 为了便于计算路径费用, 将连向祖先的流量视作正数, 相反则视作负数.</p><p>时间复杂度 $O(n \log n)$.</p><h4 id="代码实现-1"><a href="#代码实现-1" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Luogu P6122</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstring></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">1e5</span> + <span class="number">5</span>;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> INF = <span class="number">0x3f3f3f3f</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">template</span><<span class="keyword">typename</span> T> <span class="keyword">inline</span> <span class="type">bool</span> <span class="title">ckmin</span><span class="params">(T& a, <span class="type">const</span> T& b)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (a > b)? a = b, <span class="literal">true</span>: <span class="literal">false</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, m;</span><br><span class="line"><span class="type">int</span> C[MAXN], flow[MAXN], d[MAXN], p[MAXN];</span><br><span class="line"><span class="comment">// flow: u --> pre(u) 流量, d: u --> 匹配位置 距离</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">augment</span><span class="params">(<span class="type">int</span> u)</span> </span>{</span><br><span class="line"> <span class="type">int</span> lc = u << <span class="number">1</span>, rc = u << <span class="number">1</span> | <span class="number">1</span>;</span><br><span class="line"> d[u] = INF, p[u] = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">if</span> (C[u] > <span class="number">0</span>) d[u] = <span class="number">0</span>, p[u] = u;</span><br><span class="line"> <span class="keyword">if</span> (lc <= n && <span class="built_in">ckmin</span>(d[u], d[lc] + ((flow[lc] > <span class="number">0</span>)? <span class="number">-1</span>: <span class="number">1</span>)))</span><br><span class="line"> p[u] = p[lc];</span><br><span class="line"> <span class="keyword">if</span> (rc <= n && <span class="built_in">ckmin</span>(d[u], d[rc] + ((flow[rc] > <span class="number">0</span>)? <span class="number">-1</span>: <span class="number">1</span>)))</span><br><span class="line"> p[u] = p[rc];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d"</span>, &n, &m);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) <span class="built_in">scanf</span>(<span class="string">"%d"</span>, C + i);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">memset</span>(d, <span class="number">0x3f</span>, <span class="keyword">sizeof</span> d);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> u = n; u; --u) <span class="built_in">augment</span>(u);</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> ans = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">1</span>; k <= m; ++k) {</span><br><span class="line"> <span class="type">int</span> s, t = <span class="number">0</span>, cost = INF, ds = <span class="number">0</span>;</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &s);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> u = s; u > <span class="number">0</span>; u /= <span class="number">2</span>) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">ckmin</span>(cost, ds + d[u])) t = u;</span><br><span class="line"> ds += ((flow[u] < <span class="number">0</span>)? <span class="number">-1</span>: <span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> ans += cost;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> u = s; u != t; u /= <span class="number">2</span>) ++flow[u];</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> u = p[t]; u != t; u /= <span class="number">2</span>) --flow[u];</span><br><span class="line"> --C[p[t]];</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> u = p[t]; u != t; u /= <span class="number">2</span>) <span class="built_in">augment</span>(u);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> u = s; u > <span class="number">0</span>; u /= <span class="number">2</span>) <span class="built_in">augment</span>(u);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d%c"</span>, ans, <span class="string">" \n"</span>[k == m]);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="HDU-6634「2019-Multi-University-Training-Contest」Salty-fish"><a href="#HDU-6634「2019-Multi-University-Training-Contest」Salty-fish" class="headerlink" title="HDU 6634「2019 Multi-University Training Contest」Salty fish"></a>HDU 6634「2019 Multi-University Training Contest」Salty fish</h3><h4 id="题目链接-2"><a href="#题目链接-2" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="http://acm.hdu.edu.cn/showproblem.php?pid=6634">http://acm.hdu.edu.cn/showproblem.php?pid=6634</a></li></ul><h4 id="解题思路-2"><a href="#解题思路-2" class="headerlink" title="解题思路"></a>解题思路</h4><p>考虑最大权闭合子图的建图方式. 设源汇点分别为 $S$, $T$.</p><ol><li>对于树上每个节点 $i$, 连边 $(S, i)$, 容量为 $a_i$.</li><li>对于每个摄像头 $j$, 连边 $(j, T)$, 容量为 $c_j$.</li><li>对于摄像头 $j$, 若节点 $i$ 在 $j$ 的监控范围内, 连边 $(i, j)$, 容量为 $\infty$.</li></ol><p>此时答案为 $\sum {a_i} - \text{mincut}$.</p><p>根据最大流-最小割定理, 我们只需要计算出网络的最大流即可. 对于节点 $i$, 其流量一定流向能够监控到 $i$ 的, 且深度尽量小的摄像头. 因为深度大的摄像头更可能监控到深度大的节点. 换言之, 每个摄像头一定选择其范围内深度尽量大的节点.</p><p>那么我们可以对每个节点 $u$, 记录 $f(u, i)$ 表示 $u$ 子树内, 同根节点距离为 $i$ 节点的 $a$ 之和. 由深度从大到小的顺序选择每个摄像头, 从满足要求的最大深度开始向前推进, 更新流量和答案即可.</p><p>注意到 $f(u, i)$ 和深度有关, 可利用长链剖分维护. 此时需要在一个数组中快速修改 / 删除 / 加入一个数, 用 <code>map</code> 维护 $f(u, i)$ 就好了. <del>当然也可以写线段树合并.</del></p><p>时间复杂度 $O\big((n + m) \log n\big)$.</p><h4 id="代码实现-2"><a href="#代码实现-2" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// HDU 6634</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><map></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><vector></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstring></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> LL;</span><br><span class="line"><span class="keyword">typedef</span> map<<span class="type">int</span>, LL>::iterator IT;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">3e5</span> + <span class="number">5</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, m;</span><br><span class="line"><span class="type">int</span> pre[MAXN], A[MAXN], K[MAXN], C[MAXN];</span><br><span class="line">vector<<span class="type">int</span>> P[MAXN];</span><br><span class="line"></span><br><span class="line">LL ans;</span><br><span class="line"><span class="type">int</span> Idx[MAXN], idx;</span><br><span class="line">map<<span class="type">int</span>, LL> M[MAXN]; <span class="comment">// depth, flow</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> Graph {</span><br><span class="line"> <span class="keyword">struct</span> <span class="title class_">Edge</span> { <span class="type">int</span> nxt, to; } edges[MAXN << <span class="number">1</span>];</span><br><span class="line"> <span class="type">int</span> head[MAXN], eidx;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">init</span><span class="params">()</span> </span>{ <span class="built_in">memset</span>(head, <span class="number">-1</span>, <span class="keyword">sizeof</span> head), eidx = <span class="number">1</span>; }</span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">AddEdge</span><span class="params">(<span class="type">int</span> from, <span class="type">int</span> to)</span> </span>{</span><br><span class="line"> edges[++eidx] = (Edge){ head[from], to }, head[from] = eidx;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> depth[MAXN], d[MAXN], son[MAXN];</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">dfs</span><span class="params">(<span class="type">int</span> u)</span> </span>{</span><br><span class="line"> d[u] = <span class="number">1</span>, son[u] = <span class="number">-1</span>;</span><br><span class="line"> depth[u] = depth[pre[u]] + <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> v, i = head[u]; ~i; i = edges[i].nxt) {</span><br><span class="line"> <span class="built_in">dfs</span>(v = edges[i].to);</span><br><span class="line"> <span class="keyword">if</span> (son[u] == <span class="number">-1</span> || d[son[u]] < d[v])</span><br><span class="line"> son[u] = v, d[u] = d[v] + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> Idx[u] = (~son[u])? Idx[son[u]]: ++idx;</span><br><span class="line"> map<<span class="type">int</span>, LL>& f = M[Idx[u]];</span><br><span class="line"> f[depth[u]] += A[u];</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> v, i = head[u]; ~i; i = edges[i].nxt) {</span><br><span class="line"> <span class="keyword">if</span> ((v = edges[i].to) == son[u]) <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">for</span> (IT ite = M[Idx[v]].<span class="built_in">begin</span>(); ite != M[Idx[v]].<span class="built_in">end</span>(); ++ite)</span><br><span class="line"> f[ite->first] += ite->second;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">size_t</span> k = <span class="number">0</span>; k < P[u].<span class="built_in">size</span>(); ++k) {</span><br><span class="line"> <span class="type">const</span> <span class="type">int</span>& i = P[u][k];</span><br><span class="line"> IT ite = f.<span class="built_in">upper_bound</span>(depth[u] + K[i]);</span><br><span class="line"> <span class="keyword">if</span> (ite == f.<span class="built_in">begin</span>()) <span class="keyword">continue</span>;</span><br><span class="line"> --ite;</span><br><span class="line"> <span class="keyword">while</span> (C[i] > <span class="number">0</span>) {</span><br><span class="line"> LL w = <span class="built_in">min</span>((LL) C[i], ite->second);</span><br><span class="line"> ite->second -= w, C[i] -= w, ans -= w;</span><br><span class="line"> <span class="keyword">if</span> (ite->second > <span class="number">0</span>) <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">if</span> (ite == f.<span class="built_in">begin</span>()) { f.<span class="built_in">erase</span>(ite); <span class="keyword">break</span>; }</span><br><span class="line"> <span class="type">int</span> dep = ite->first;</span><br><span class="line"> --ite, f.<span class="built_in">erase</span>(dep);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="type">int</span> Ti;</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &Ti);</span><br><span class="line"> <span class="keyword">while</span> (Ti--) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) P[i].<span class="built_in">clear</span>();</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= idx; ++i) M[i].<span class="built_in">clear</span>();</span><br><span class="line"> ans = idx = <span class="number">0</span>, Graph::<span class="built_in">init</span>();</span><br><span class="line"></span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d"</span>, &n, &m);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">2</span>; i <= n; ++i)</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, pre + i), Graph::<span class="built_in">AddEdge</span>(pre[i], i);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i)</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, A + i), ans += A[i];</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> u, i = <span class="number">1</span>; i <= m; ++i)</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d%d"</span>, &u, K + i, C + i), P[u].<span class="built_in">push_back</span>(i);</span><br><span class="line"></span><br><span class="line"> Graph::<span class="built_in">dfs</span>(<span class="number">1</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%lld\n"</span>, ans);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="UOJ-318「NOI2017」蔬菜"><a href="#UOJ-318「NOI2017」蔬菜" class="headerlink" title="UOJ #318「NOI2017」蔬菜"></a>UOJ #318「NOI2017」蔬菜</h3><h4 id="题目链接-3"><a href="#题目链接-3" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://uoj.ac/problem/318">https://uoj.ac/problem/318</a></li></ul><h4 id="解题思路-3"><a href="#解题思路-3" class="headerlink" title="解题思路"></a>解题思路</h4><p>首先有一个朴素的网络流思路. 设源汇点分别为 $S$, $T$, 同时将每天视作一个节点, 记 $p$ 为最大天数.</p><ol><li>对于每个蔬菜 $i$, 记其最大售卖天数 $k$ 为 $\min\{ p, \lceil \frac{c_i}{x_i} \rceil \}$.<ul><li>向第 $1 \sim k - 1$ 天依次连边, 容量为 $x_i$, 费用为 $a_i$.</li><li>向第 $k$ 天连边, 容量为 $c_i - k x_i - 1$, 费用为 $a_i$.</li><li>向第 $k$ 天连边, 容量为 $1$, 费用为 $a_i + s_i$</li></ul></li><li>对于第 $i$ 天<ul><li>连边 $(i, i - 1)$, 容量为 $\infty$, 费用为 $0$.</li><li>连边 $(i, T)$, 容量为 $m$, 费用为 $0$.</li></ul></li></ol><p>观察每次增广时的情况. 在天数不断增加时, 原有流量改变一定不优, 否则在前一天可改变流量使得前一天答案更优. 也就是说, 第 $i$ 天售出的蔬菜一定是第 $i + 1$ 天售出蔬菜的一部分, 且网络中不存在退流.</p><p>同时, 注意到天数对应点之间的连边, 对于每个蔬菜, 尽量选择靠后天数是更优秀的. 从建图解释, 选择靠后天数可通过容量为 $\infty$ 的边增广. 从实际意义解释, 将蔬菜尽量放在快过期的时候卖出更优. 同时要选择权值尽量大的蔬菜卖出.</p><p>那么用堆维护当前可选的蔬菜, 每天的销售情况视作增广 $m$ 的流量, 选择权值最大的蔬菜即可. 同时需要知道当前天对应节点在向 $T$ 的边满流之后, 向前增广的位置. 可以利用并查集维护.</p><p>时间复杂度 $O(n \log n + pm\log n)$.</p><h4 id="代码实现-3"><a href="#代码实现-3" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// UOJ #318</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><queue></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cctype></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> IO {</span><br><span class="line"> <span class="type">const</span> <span class="type">int</span> MAXSIZE = <span class="number">1</span> << <span class="number">18</span> | <span class="number">1</span>;</span><br><span class="line"> <span class="type">char</span> buf[MAXSIZE], *p1, *p2;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">Gc</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> p1 == p2 &&</span><br><span class="line"> (p2 = (p1 = buf) + <span class="built_in">fread</span>(buf, <span class="number">1</span>, MAXSIZE, stdin), p1 == p2)? EOF: *p1++;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">template</span><<span class="keyword">typename</span> T> <span class="keyword">inline</span> <span class="type">void</span> <span class="title">read</span><span class="params">(T& x)</span> </span>{</span><br><span class="line"> x = <span class="number">0</span>; <span class="type">int</span> f = <span class="number">0</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (!<span class="built_in">isdigit</span>(ch)) f |= ch == <span class="string">'-'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">isdigit</span>(ch)) x = x * <span class="number">10</span> + ch - <span class="string">'0'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">if</span> (f) x = -x;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">using</span> IO::read;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> LL;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">1e5</span> + <span class="number">5</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, m, q;</span><br><span class="line"><span class="type">int</span> A[MAXN], X[MAXN], S[MAXN], C[MAXN], Q[MAXN];</span><br><span class="line"></span><br><span class="line">LL Ans[MAXN];</span><br><span class="line"><span class="type">int</span> cnt[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Item</span> {</span><br><span class="line"> <span class="type">int</span> idx, v;</span><br><span class="line"> <span class="built_in">Item</span>(<span class="type">int</span> _i, <span class="type">int</span> _v): <span class="built_in">idx</span>(_i), <span class="built_in">v</span>(_v) { }</span><br><span class="line"> <span class="type">bool</span> <span class="keyword">operator</span> < (<span class="type">const</span> Item& rhs) <span class="type">const</span> {</span><br><span class="line"> <span class="keyword">return</span> v < rhs.v;</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line">priority_queue<Item> PQ;</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> DSU {</span><br><span class="line"> <span class="type">int</span> fa[MAXN];</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">init</span><span class="params">(<span class="type">int</span> _n)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i <= _n; ++i) fa[i] = i;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="type">int</span> <span class="title">findfa</span><span class="params">(<span class="type">int</span> u)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (fa[u] == u)? u: fa[u] = <span class="built_in">findfa</span>(fa[u]);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"data/ex_vegetables3.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="built_in">read</span>(n), <span class="built_in">read</span>(m), <span class="built_in">read</span>(q);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i)</span><br><span class="line"> <span class="built_in">read</span>(A[i]), <span class="built_in">read</span>(S[i]), <span class="built_in">read</span>(C[i]), <span class="built_in">read</span>(X[i]);</span><br><span class="line"> <span class="type">int</span> Mx = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= q; ++i)</span><br><span class="line"> <span class="built_in">read</span>(Q[i]), Mx = <span class="built_in">max</span>(Mx, Q[i]);</span><br><span class="line"></span><br><span class="line"> DSU::<span class="built_in">init</span>(Mx);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i)</span><br><span class="line"> PQ.<span class="built_in">push</span>(<span class="built_in">Item</span>(i, A[i] + S[i]));</span><br><span class="line"></span><br><span class="line"> LL ans = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> p = <span class="number">1</span>; p <= Mx; ++p) {</span><br><span class="line"> <span class="type">int</span> flow = m;</span><br><span class="line"> <span class="keyword">while</span> (flow > <span class="number">0</span> && !PQ.<span class="built_in">empty</span>()) {</span><br><span class="line"> <span class="type">int</span> i = PQ.<span class="built_in">top</span>().idx, v = PQ.<span class="built_in">top</span>().v; PQ.<span class="built_in">pop</span>();</span><br><span class="line"> <span class="type">int</span> k = (X[i] == <span class="number">0</span>)? Mx: <span class="built_in">min</span>(Mx, (C[i] + X[i] - <span class="number">1</span>) / X[i]);</span><br><span class="line"> k = DSU::<span class="built_in">findfa</span>(k);</span><br><span class="line"> <span class="keyword">if</span> (k == <span class="number">0</span>) <span class="keyword">continue</span>;</span><br><span class="line"> ++cnt[k];</span><br><span class="line"> <span class="keyword">if</span> (cnt[k] == m) DSU::fa[k] = DSU::<span class="built_in">findfa</span>(k - <span class="number">1</span>);</span><br><span class="line"> --flow, --C[i], ans += v;</span><br><span class="line"> <span class="keyword">if</span> (C[i] > <span class="number">0</span>) PQ.<span class="built_in">push</span>(<span class="built_in">Item</span>(i, A[i]));</span><br><span class="line"> }</span><br><span class="line"> Ans[p] = ans;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= q; ++i)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%lld\n"</span>, Ans[Q[i]]);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="UOJ-480「NOI2019」序列"><a href="#UOJ-480「NOI2019」序列" class="headerlink" title="UOJ #480「NOI2019」序列"></a>UOJ #480「NOI2019」序列</h3><h4 id="题目链接-4"><a href="#题目链接-4" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://uoj.ac/problem/480">https://uoj.ac/problem/480</a></li></ul><h4 id="解题思路-4"><a href="#解题思路-4" class="headerlink" title="解题思路"></a>解题思路</h4><p>首先有一个朴素的费用流思路. 设源汇点分别为 $S$, $T$, 对两序列的每个位置分别建点 $i$, $i’$.</p><ol><li>新建节点 $S’$, 连边 $(S, S’)$, 容量为 $K$, 费用为 $0$.</li><li>对于序列的每个位置 $i$, 连边<ul><li>$(S, i)$, 容量为 $1$, 费用为 $a_i$.</li><li>$(S, i’)$, 容量为 $1$, 费用为 $b_i$.</li><li>$(i, i’)$, 容量为 $1$, 费用为 $0$.</li></ul></li><li>新建节点 $C$, $D$. 用于描述 “至少有 $L$ 个下标在两个序列中都被指定” 的限制.<ul><li>连边 $(C, D)$, 容量为 $K - L$, 费用为 $0$.</li><li>对于每个位置 $i$, 连边 $(i, C)$, $(D, i’)$, 容量为 $1$, 费用为 $0$.</li></ul></li></ol><p>现在考虑如何模拟该费用流.</p><p>存在至多 $K - L$ 个位置不受在两个序列中都被指定的限制. 此时一定先选择 $a_i$, $b_i$ 中权值大的位置, 体现在网络中即边 $(C, D)$ 满流.</p><p>现在还剩下 $L$ 个位置需要选择, 即剩下 $L$ 的流量需要增广. 记录每个位置 $i$ 被选择的情况 $f_i$, 其二进制第 $0$ 位表示 $a_i$ 是否被选择, 或是边 $(S, i)$ 的流量. 第 $1$ 位则表示 $b_i$ 的情况.</p><p>为使总权值最大, 每次需要选择权值尽量大的位置. 那么利用数个大根堆 (<code>r0</code>, <code>r1</code>, <code>r</code>), 分别维护恰在序列 $a_i$ (<code>r0</code>) 或 $b_i$ (<code>r1</code>) 中没有选择的位置, 以及都没有选择的位置 (<code>r</code>). 对于前两种情况, 在选择位置时需要另一序列某一元素配对, 再利用两个堆 (<code>p0</code>, <code>p1</code>) 记录可配对的位置.</p><p>首先单独考虑 $f_i = 3$ 的情况, 此时简直是理想状态, 满足权值尽量大的同时也满足了限制.</p><p>为使总权值尽量大, 则需要将边 $(C, D)$ 的某个流量改流在形同 $(i, i’)$ 的边上. 那么记录此种情况的流量总数 <code>flow</code>, 在允许此种增广时选择一组流经 $(C, D)$ 的流量即可. 也就是在 <code>r0</code>, <code>r1</code> 中选择两个元素.</p><p>剩下的情况无外乎 $f_i$ 为 $0, 1, 2$. 根据其特性选择增广路, 也就是不同的位置匹配, 记录其权值并取权值最大的情况即可.</p><p>细节可能有些多, 还是建议想清楚之后再动键盘. 注意要根据 $f_i$ 的取值删除堆中的不合法元素, 以及及时更新 $f_i$ 和 <code>flow</code>.</p><p>时间复杂度 $O(T \cdot n \log n)$.</p><h4 id="代码实现-4"><a href="#代码实现-4" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// UOJ #480</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><queue></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cctype></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> IO {</span><br><span class="line"> <span class="type">const</span> <span class="type">int</span> MAXSIZE = <span class="number">1</span> << <span class="number">18</span> | <span class="number">1</span>;</span><br><span class="line"> <span class="type">char</span> buf[MAXSIZE], *p1, *p2;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">Gc</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> p1 == p2 &&</span><br><span class="line"> (p2 = (p1 = buf) + <span class="built_in">fread</span>(buf, <span class="number">1</span>, MAXSIZE, stdin), p1 == p2)? EOF: *p1++;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">template</span><<span class="keyword">typename</span> T> <span class="keyword">inline</span> <span class="type">void</span> <span class="title">read</span><span class="params">(T& x)</span> </span>{</span><br><span class="line"> x = <span class="number">0</span>; <span class="type">int</span> f = <span class="number">0</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (!<span class="built_in">isdigit</span>(ch)) f |= ch == <span class="string">'-'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">isdigit</span>(ch)) x = x * <span class="number">10</span> + ch - <span class="string">'0'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">if</span> (f) x = -x;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">using</span> IO::read;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> LL;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">2e5</span> + <span class="number">5</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, K, L;</span><br><span class="line"><span class="type">int</span> A[MAXN], B[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">ItemA</span> {</span><br><span class="line"> <span class="type">int</span> idx;</span><br><span class="line"> <span class="built_in">ItemA</span>(<span class="type">int</span> _i): <span class="built_in">idx</span>(_i) { }</span><br><span class="line"> <span class="type">bool</span> <span class="keyword">operator</span> < (<span class="type">const</span> ItemA& rhs) <span class="type">const</span> {</span><br><span class="line"> <span class="keyword">return</span> A[idx] < A[rhs.idx];</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">ItemB</span> {</span><br><span class="line"> <span class="type">int</span> idx;</span><br><span class="line"> <span class="built_in">ItemB</span>(<span class="type">int</span> _i): <span class="built_in">idx</span>(_i) { }</span><br><span class="line"> <span class="type">bool</span> <span class="keyword">operator</span> < (<span class="type">const</span> ItemB& rhs) <span class="type">const</span> {</span><br><span class="line"> <span class="keyword">return</span> B[idx] < B[rhs.idx];</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">ItemAB</span> {</span><br><span class="line"> <span class="type">int</span> idx;</span><br><span class="line"> <span class="built_in">ItemAB</span>(<span class="type">int</span> _i): <span class="built_in">idx</span>(_i) { }</span><br><span class="line"> <span class="type">bool</span> <span class="keyword">operator</span> < (<span class="type">const</span> ItemAB& rhs) <span class="type">const</span> {</span><br><span class="line"> <span class="keyword">return</span> A[idx] + B[idx] < A[rhs.idx] + B[rhs.idx];</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> idx[MAXN], f[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"data/ex_sequence3.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="type">int</span> Ti; <span class="built_in">read</span>(Ti);</span><br><span class="line"> <span class="keyword">while</span> (Ti--) {</span><br><span class="line"> <span class="built_in">read</span>(n), <span class="built_in">read</span>(K), <span class="built_in">read</span>(L);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) <span class="built_in">read</span>(A[i]);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) <span class="built_in">read</span>(B[i]);</span><br><span class="line"></span><br><span class="line"> priority_queue<ItemA> r0, p0;</span><br><span class="line"> priority_queue<ItemB> r1, p1;</span><br><span class="line"> priority_queue<ItemAB> r;</span><br><span class="line"></span><br><span class="line"> LL ans = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) f[i] = <span class="number">0</span>, idx[i] = i;</span><br><span class="line"> <span class="built_in">sort</span>(idx + <span class="number">1</span>, idx + <span class="number">1</span> + n, [](<span class="type">const</span> <span class="type">int</span>& x, <span class="type">const</span> <span class="type">int</span>& y) {</span><br><span class="line"> <span class="keyword">return</span> A[x] > A[y];</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= K - L; ++i)</span><br><span class="line"> ans += A[idx[i]], f[idx[i]] |= <span class="number">1</span>;</span><br><span class="line"> <span class="built_in">sort</span>(idx + <span class="number">1</span>, idx + <span class="number">1</span> + n, [](<span class="type">const</span> <span class="type">int</span>& x, <span class="type">const</span> <span class="type">int</span>& y) {</span><br><span class="line"> <span class="keyword">return</span> B[x] > B[y];</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= K - L; ++i)</span><br><span class="line"> ans += B[idx[i]], f[idx[i]] |= <span class="number">2</span>;</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> flow = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) {</span><br><span class="line"> <span class="keyword">switch</span> (f[i]) {</span><br><span class="line"> <span class="keyword">case</span> <span class="number">0</span>: r<span class="number">0.</span><span class="built_in">push</span>(i), r<span class="number">1.</span><span class="built_in">push</span>(i), r.<span class="built_in">push</span>(i); <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">1</span>: r<span class="number">1.</span><span class="built_in">push</span>(i), p<span class="number">1.</span><span class="built_in">push</span>(i); <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">2</span>: r<span class="number">0.</span><span class="built_in">push</span>(i), p<span class="number">0.</span><span class="built_in">push</span>(i); <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">3</span>: ++flow; <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span> (L--) {</span><br><span class="line"> <span class="keyword">while</span> (!r.<span class="built_in">empty</span>() && f[r.<span class="built_in">top</span>().idx] > <span class="number">0</span>) r.<span class="built_in">pop</span>();</span><br><span class="line"> <span class="keyword">while</span> (!r<span class="number">0.</span><span class="built_in">empty</span>() && (f[r<span class="number">0.</span><span class="built_in">top</span>().idx] & <span class="number">1</span>)) r<span class="number">0.</span><span class="built_in">pop</span>();</span><br><span class="line"> <span class="keyword">while</span> (!p<span class="number">0.</span><span class="built_in">empty</span>() && (f[p<span class="number">0.</span><span class="built_in">top</span>().idx] ^ <span class="number">2</span>)) p<span class="number">0.</span><span class="built_in">pop</span>();</span><br><span class="line"> <span class="keyword">while</span> (!r<span class="number">1.</span><span class="built_in">empty</span>() && (f[r<span class="number">1.</span><span class="built_in">top</span>().idx] & <span class="number">2</span>)) r<span class="number">1.</span><span class="built_in">pop</span>();</span><br><span class="line"> <span class="keyword">while</span> (!p<span class="number">1.</span><span class="built_in">empty</span>() && (f[p<span class="number">1.</span><span class="built_in">top</span>().idx] ^ <span class="number">1</span>)) p<span class="number">1.</span><span class="built_in">pop</span>();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (flow > <span class="number">0</span>) {</span><br><span class="line"> <span class="type">int</span> i = r<span class="number">0.</span><span class="built_in">top</span>().idx, j = r<span class="number">1.</span><span class="built_in">top</span>().idx;</span><br><span class="line"> ans += A[i] + B[j], --flow, f[i] |= <span class="number">1</span>, f[j] |= <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">if</span> (f[i] != <span class="number">3</span>) p<span class="number">1.</span><span class="built_in">push</span>(i);</span><br><span class="line"> <span class="keyword">if</span> (f[j] != <span class="number">3</span>) p<span class="number">0.</span><span class="built_in">push</span>(j);</span><br><span class="line"> flow += (i == j)? <span class="number">1</span>: ((f[i] == <span class="number">3</span>) + (f[j] == <span class="number">3</span>));</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="type">static</span> <span class="type">int</span> i1, j1, i2, j2, p3;</span><br><span class="line"> LL Mx, v1 = <span class="number">0</span>, v2 = <span class="number">0</span>, v3 = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">if</span> (!r<span class="number">0.</span><span class="built_in">empty</span>() && !p<span class="number">1.</span><span class="built_in">empty</span>())</span><br><span class="line"> i1 = r<span class="number">0.</span><span class="built_in">top</span>().idx, j1 = p<span class="number">1.</span><span class="built_in">top</span>().idx, v1 = A[i1] + B[j1];</span><br><span class="line"> <span class="keyword">if</span> (!p<span class="number">0.</span><span class="built_in">empty</span>() && !r<span class="number">1.</span><span class="built_in">empty</span>())</span><br><span class="line"> i2 = p<span class="number">0.</span><span class="built_in">top</span>().idx, j2 = r<span class="number">1.</span><span class="built_in">top</span>().idx, v2 = A[i2] + B[j2];</span><br><span class="line"> <span class="keyword">if</span> (!r.<span class="built_in">empty</span>())</span><br><span class="line"> p3 = r.<span class="built_in">top</span>().idx, v3 = A[p3] + B[p3];</span><br><span class="line"> Mx = <span class="built_in">max</span>(v1, <span class="built_in">max</span>(v2, v3)), ans += Mx;</span><br><span class="line"> <span class="keyword">if</span> (v1 == Mx) {</span><br><span class="line"> f[i1] |= <span class="number">1</span>, f[j1] |= <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">if</span> (f[i1] != <span class="number">3</span>) p<span class="number">1.</span><span class="built_in">push</span>(i1); <span class="keyword">else</span> ++flow;</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (v2 == Mx) {</span><br><span class="line"> f[i2] |= <span class="number">1</span>, f[j2] |= <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">if</span> (f[j2] != <span class="number">3</span>) p<span class="number">0.</span><span class="built_in">push</span>(j2); <span class="keyword">else</span> ++flow;</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (v3 == Mx)</span><br><span class="line"> r.<span class="built_in">pop</span>(), f[p3] |= <span class="number">3</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%lld\n"</span>, ans);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><hr><p>以下就是 laofu 课件中 “老鼠进洞” 的模型了. 或者说是, 二分图带权匹配的模型.</p><p>考虑到二分图带权匹配已经是经典问题, 下文就不再赘述朴素的网络流做法.</p><p>laofu 课件中利用较多篇幅, 从 DP 凸性的角度入手解决了这些问题… 作为没有梦想的咸鱼选手, 我暂且还是选择感性理解的方式.</p><h3 id="BZOJ-4977「Lydsy1708-月赛」跳伞求生"><a href="#BZOJ-4977「Lydsy1708-月赛」跳伞求生" class="headerlink" title="BZOJ 4977「Lydsy1708 月赛」跳伞求生"></a>BZOJ 4977「Lydsy1708 月赛」跳伞求生</h3><h4 id="题目链接-5"><a href="#题目链接-5" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><del><a href="http://lydsy.com/JudgeOnline/problem.php?id=4977">http://lydsy.com/JudgeOnline/problem.php?id=4977</a></del></li><li><a href="https://darkbzoj.tk/problem/4977">https://darkbzoj.tk/problem/4977</a></li></ul><h4 id="解题思路-5"><a href="#解题思路-5" class="headerlink" title="解题思路"></a>解题思路</h4><p>laofu 课件中的 Problem 3.</p><p>首先思考简化版的问题.</p><blockquote><p>数轴上有 $n$ 只老鼠和 $m$ 个老鼠洞. 第 $i$ 只老鼠的坐标为 $x_i$, 第 $j$ 个老鼠洞的坐标为 $y_i$.<br>现在要让老鼠进洞, 也就是寻找老鼠和洞的匹配.</p><p>假定每只老鼠只能往左走, 每个洞容量为 $1$. 求所有老鼠都进洞的最小总代价(即行走的最小总距离).</p></blockquote><p>也就是 laofu 课件中的 Problem 1.</p><p>首先将洞的权值视作 $-y_i$, 老鼠的权值视作 $x_i$, 所求即最小权匹配. 将数轴上的所有点排序, 那么用栈记录所有的未匹配洞的位置, 在遇到老鼠时选择栈顶的洞匹配上即可.</p><p>再来考虑这个问题. 此时每个洞带权, 且不要求所有老鼠都进洞, 所求为最大权匹配.</p><p>对于一组匹配, 其对答案的贡献为 $x_i - y_j + w_j$. 考虑到 $w_j$ 的影响, 对所有点按坐标排序后洞的权值并不单调. 那么将栈换作堆维护最值即可.</p><p>但直接选择的匹配并不一定为最优解. 联系费用流中的退流操作, 在选择一组匹配后向堆中增加权值为 $-x_i$ 的元素, 从而体现匹配更改的情况.</p><p>时间复杂度 $O(n \log n)$.</p><h4 id="代码实现-5"><a href="#代码实现-5" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// BZOJ #4977</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><queue></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> LL;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">1e5</span> + <span class="number">5</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Point</span> {</span><br><span class="line"> <span class="type">int</span> x, w;</span><br><span class="line"> <span class="built_in">Point</span>() = <span class="keyword">default</span>;</span><br><span class="line"> <span class="built_in">Point</span>(<span class="type">int</span> _x, <span class="type">int</span> _w): <span class="built_in">x</span>(_x), <span class="built_in">w</span>(_w) { }</span><br><span class="line"> <span class="type">bool</span> <span class="keyword">operator</span> < (<span class="type">const</span> Point& rhs) <span class="type">const</span> {</span><br><span class="line"> <span class="keyword">return</span> x < rhs.x || (x == rhs.x && w < rhs.w);</span><br><span class="line"> }</span><br><span class="line">} P[MAXN << <span class="number">1</span>];</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, m, p;</span><br><span class="line">priority_queue<<span class="type">int</span>> d;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d"</span>, &n, &m);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> a, i = <span class="number">1</span>; i <= n; ++i)</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &a), P[++p] = <span class="built_in">Point</span>(a, <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> b, c, i = <span class="number">1</span>; i <= m; ++i)</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d"</span>, &b, &c), P[++p] = <span class="built_in">Point</span>(b, c);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">sort</span>(P + <span class="number">1</span>, P + <span class="number">1</span> + p);</span><br><span class="line"> LL ans = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= p; ++i) {</span><br><span class="line"> <span class="keyword">if</span> (P[i].w == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">if</span> (d.<span class="built_in">empty</span>() || d.<span class="built_in">top</span>() + P[i].x <= <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> ans += d.<span class="built_in">top</span>() + P[i].x;</span><br><span class="line"> d.<span class="built_in">pop</span>(), d.<span class="built_in">push</span>(-P[i].x);</span><br><span class="line"> } <span class="keyword">else</span></span><br><span class="line"> d.<span class="built_in">push</span>(-P[i].x + P[i].w);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%lld\n"</span>, ans);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="UOJ-455【UER-8】雪灾与外卖"><a href="#UOJ-455【UER-8】雪灾与外卖" class="headerlink" title="UOJ #455【UER #8】雪灾与外卖"></a>UOJ #455【UER #8】雪灾与外卖</h3><h4 id="题目链接-6"><a href="#题目链接-6" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://uoj.ac/problem/455">https://uoj.ac/problem/455</a></li></ul><h4 id="解题思路-6"><a href="#解题思路-6" class="headerlink" title="解题思路"></a>解题思路</h4><p>laofu 课件中的 Problem 6.</p><p>不妨先去除每个洞容量的限制, 考虑容量为 $1$ 的情况.</p><p>首先匹配交叉一定不优. 同样将数轴上的点从小到大排序, 对于每只老鼠或是每个洞, 讨论其匹配和反悔的权值即可.</p><p>具体的讨论可参考 <a href="https://whzzt.blog.uoj.ac/blog/4749">UOJ 官方题解</a>, 或者是文末的参考资料 (</p><p>每个洞容量的限制体现在网络流中即边的容量, 直接往之前的堆中丢一个 <code>pair</code> 记录增广的权值和容量即可. 可以证明, 此时对堆操作次数仍为线性.</p><p>在老鼠存在 “分身” 的情况下, 也是可以这样做的.</p><p>时间复杂度 $O(n \log n)$.</p><h4 id="代码实现-6"><a href="#代码实现-6" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// UOJ #455</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><queue></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cctype></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> IO {</span><br><span class="line"> <span class="type">const</span> <span class="type">int</span> MAXSIZE = <span class="number">1</span> << <span class="number">18</span> | <span class="number">1</span>;</span><br><span class="line"> <span class="type">char</span> buf[MAXSIZE], *p1, *p2;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">Gc</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> p1 == p2 &&</span><br><span class="line"> (p2 = (p1 = buf) + <span class="built_in">fread</span>(buf, <span class="number">1</span>, MAXSIZE, stdin), p1 == p2)? EOF: *p1++;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">template</span><<span class="keyword">typename</span> T> <span class="keyword">inline</span> <span class="type">void</span> <span class="title">read</span><span class="params">(T& x)</span> </span>{</span><br><span class="line"> x = <span class="number">0</span>; <span class="type">int</span> f = <span class="number">0</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (!<span class="built_in">isdigit</span>(ch)) f |= ch == <span class="string">'-'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">isdigit</span>(ch)) x = x * <span class="number">10</span> + ch - <span class="string">'0'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">if</span> (f) x = -x;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">using</span> IO::read;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> LL;</span><br><span class="line"><span class="keyword">typedef</span> pair<LL, LL> Pll;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">1e5</span> + <span class="number">5</span>;</span><br><span class="line"><span class="type">const</span> LL INFLL = <span class="number">1e18</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Point</span> {</span><br><span class="line"> <span class="type">int</span> x, w, c;</span><br><span class="line"> <span class="built_in">Point</span>() = <span class="keyword">default</span>;</span><br><span class="line"> <span class="built_in">Point</span>(<span class="type">int</span> _x, <span class="type">int</span> _w, <span class="type">int</span> _c): <span class="built_in">x</span>(_x), <span class="built_in">w</span>(_w), <span class="built_in">c</span>(_c) { }</span><br><span class="line"> <span class="type">bool</span> <span class="keyword">operator</span> < (<span class="type">const</span> Point& rhs) <span class="type">const</span> {</span><br><span class="line"> <span class="keyword">return</span> x < rhs.x;</span><br><span class="line"> }</span><br><span class="line">} P[MAXN << <span class="number">1</span>];</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, m, p;</span><br><span class="line">priority_queue<Pll, vector<Pll>, greater<Pll> > d0, d1;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">signed</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"data/ex_hole7.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="built_in">read</span>(n), <span class="built_in">read</span>(m);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> x, i = <span class="number">1</span>; i <= n; ++i)</span><br><span class="line"> <span class="built_in">read</span>(x), P[++p] = <span class="built_in">Point</span>(x, <span class="number">-1</span>, <span class="number">-1</span>);</span><br><span class="line"> LL sc = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> x, w, c, i = <span class="number">1</span>; i <= m; ++i) {</span><br><span class="line"> <span class="built_in">read</span>(x), <span class="built_in">read</span>(w), <span class="built_in">read</span>(c);</span><br><span class="line"> P[++p] = <span class="built_in">Point</span>(x, w, c), sc += c;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (sc < n)</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">"-1"</span>), <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="built_in">sort</span>(P + <span class="number">1</span>, P + <span class="number">1</span> + p);</span><br><span class="line"> LL ans = <span class="number">0</span>;</span><br><span class="line"> d<span class="number">1.</span><span class="built_in">push</span>(<span class="built_in">Pll</span>(INFLL, n));</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= p; ++i) {</span><br><span class="line"> <span class="type">int</span> x = P[i].x, w = P[i].w;</span><br><span class="line"> <span class="keyword">if</span> (w == <span class="number">-1</span>) {</span><br><span class="line"> Pll t = d<span class="number">1.</span><span class="built_in">top</span>(); d<span class="number">1.</span><span class="built_in">pop</span>();</span><br><span class="line"> ans += t.first + x, --t.second;</span><br><span class="line"> <span class="keyword">if</span> (t.second > <span class="number">0</span>) d<span class="number">1.</span><span class="built_in">push</span>(t);</span><br><span class="line"> d<span class="number">0.</span><span class="built_in">push</span>(<span class="built_in">Pll</span>(<span class="number">-2LL</span> * x - t.first, <span class="number">1</span>));</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> LL tot = <span class="number">0</span>, c = P[i].c;</span><br><span class="line"> <span class="keyword">while</span> (c > <span class="number">0</span> && !d<span class="number">0.</span><span class="built_in">empty</span>()) {</span><br><span class="line"> Pll t = d<span class="number">0.</span><span class="built_in">top</span>();</span><br><span class="line"> <span class="keyword">if</span> (t.first + x + w >= <span class="number">0</span>) <span class="keyword">break</span>;</span><br><span class="line"> d<span class="number">0.</span><span class="built_in">pop</span>();</span><br><span class="line"> LL s = <span class="built_in">min</span>((LL) c, t.second);</span><br><span class="line"> ans += s * (t.first + w + x), t.second -= s, c -= s;</span><br><span class="line"> <span class="keyword">if</span> (t.second > <span class="number">0</span>) d<span class="number">0.</span><span class="built_in">push</span>(t);</span><br><span class="line"> tot += s, d<span class="number">1.</span><span class="built_in">push</span>(<span class="built_in">Pll</span>(<span class="number">-2LL</span> * x - t.first, s));</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (tot > <span class="number">0</span>)</span><br><span class="line"> d<span class="number">0.</span><span class="built_in">push</span>(<span class="built_in">Pll</span>(-x - w, tot));</span><br><span class="line"> <span class="keyword">if</span> (c > <span class="number">0</span>)</span><br><span class="line"> d<span class="number">1.</span><span class="built_in">push</span>(<span class="built_in">Pll</span>(-x + w, c));</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%lld\n"</span>, ans);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="LOJ-6405「ICPC-World-Finals-2018」征服世界"><a href="#LOJ-6405「ICPC-World-Finals-2018」征服世界" class="headerlink" title="LOJ #6405「ICPC World Finals 2018」征服世界"></a>LOJ #6405「ICPC World Finals 2018」征服世界</h3><h4 id="题目链接-7"><a href="#题目链接-7" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://loj.ac/problem/6405">https://loj.ac/problem/6405</a></li></ul><h4 id="解题思路-7"><a href="#解题思路-7" class="headerlink" title="解题思路"></a>解题思路</h4><p>laofu 课件中的 Problem 7.</p><p>上一题的模型上树.</p><p>首先每个点都存在军队和需求的限制是假的, 每个位置的军队解决自己的问题显然更优. 把军队视为洞, 军队需求视作老鼠, 可以得到老鼠进洞的模型. 换句话说, 对于 $x_i > y_i$ 的节点, 视作容量为 $x_i - y_i$ 的洞; 对于满足 $x_i < y_i$ 的节点, 视作 $y_i - x_i$ 只老鼠.</p><p>现在需要让所有老鼠进洞并使花费最小. 记 $\mathrm{dist}(u)$ 表示树上节点 $u$ 到根的距离, 那么花费形同 $\mathrm{dist}(u) + \mathrm{dist}(v) - 2\cdot \mathrm{dist}(\mathrm{LCA}(u, v))$.</p><p>对于每个点 $u$, 将 $\mathrm{dist}(u)$ 视作 $u$ 的权值. 同时, 每只老鼠一定要进洞, 直接将权值减去 $\infty$, 在计算答案时加上就好了.</p><p>剩下的情况和上一题没有太大区别, 另外需要可并堆快速从下向上合并节点的信息.</p><p>时间复杂度 $O(n \log n)$.</p><h4 id="代码实现-7"><a href="#代码实现-7" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// LOJ #6405</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cctype></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstring></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> IO {</span><br><span class="line"> <span class="type">const</span> <span class="type">int</span> MAXSIZE = <span class="number">1</span> << <span class="number">18</span> | <span class="number">1</span>;</span><br><span class="line"> <span class="type">char</span> buf[MAXSIZE], *p1, *p2;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">Gc</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> p1 == p2 &&</span><br><span class="line"> (p2 = (p1 = buf) + <span class="built_in">fread</span>(buf, <span class="number">1</span>, MAXSIZE, stdin), p1 == p2)? EOF: *p1++;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">template</span><<span class="keyword">typename</span> T> <span class="keyword">inline</span> <span class="type">void</span> <span class="title">read</span><span class="params">(T& x)</span> </span>{</span><br><span class="line"> x = <span class="number">0</span>; <span class="type">int</span> f = <span class="number">0</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (!<span class="built_in">isdigit</span>(ch)) f |= ch == <span class="string">'-'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">isdigit</span>(ch)) x = x * <span class="number">10</span> + ch - <span class="string">'0'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">if</span> (f) x = -x;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">using</span> IO::read;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> LL;</span><br><span class="line"><span class="keyword">typedef</span> pair<LL, <span class="type">int</span>> Pli;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">2.5e5</span> + <span class="number">5</span>, MAXM = MAXN << <span class="number">5</span>;</span><br><span class="line"><span class="type">const</span> LL INFLL = MAXN * <span class="number">1e6</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n;</span><br><span class="line"><span class="type">int</span> X[MAXN], Y[MAXN];</span><br><span class="line"></span><br><span class="line">LL d[MAXN], ans;</span><br><span class="line"><span class="type">int</span> rt0[MAXN], rt1[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> Heap {</span><br><span class="line"> Pli val[MAXM];</span><br><span class="line"> <span class="type">int</span> ch[<span class="number">2</span>][MAXM], dist[MAXM], nidx;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">newnode</span><span class="params">(<span class="type">const</span> Pli& v)</span> </span>{ <span class="keyword">return</span> val[++nidx] = v, nidx; }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">int</span> <span class="title">Mrg</span><span class="params">(<span class="type">int</span> x, <span class="type">int</span> y)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (!x || !y) <span class="keyword">return</span> x + y;</span><br><span class="line"> <span class="keyword">if</span> (val[x] > val[y]) <span class="built_in">swap</span>(x, y);</span><br><span class="line"> ch[<span class="number">1</span>][x] = <span class="built_in">Mrg</span>(ch[<span class="number">1</span>][x], y);</span><br><span class="line"> <span class="keyword">if</span> (dist[ch[<span class="number">0</span>][x]] < dist[ch[<span class="number">1</span>][x]]) <span class="built_in">swap</span>(ch[<span class="number">0</span>][x], ch[<span class="number">1</span>][x]);</span><br><span class="line"> dist[x] = dist[ch[<span class="number">1</span>][x]] + <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">return</span> x;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">Pop</span><span class="params">(<span class="type">int</span>& u)</span> </span>{ u = <span class="built_in">Mrg</span>(ch[<span class="number">0</span>][u], ch[<span class="number">1</span>][u]); }</span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">Psh</span><span class="params">(<span class="type">int</span>& u, <span class="type">const</span> Pli& v)</span> </span>{ u = <span class="built_in">Mrg</span>(u, <span class="built_in">newnode</span>(v)); }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> Graph {</span><br><span class="line"> <span class="keyword">struct</span> <span class="title class_">Edge</span> { <span class="type">int</span> nxt, to, w; } edges[MAXN << <span class="number">1</span>];</span><br><span class="line"> <span class="type">int</span> head[MAXN], eidx;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">init</span><span class="params">()</span> </span>{ <span class="built_in">memset</span>(head, <span class="number">-1</span>, <span class="keyword">sizeof</span> head), eidx = <span class="number">1</span>; }</span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">AddEdge</span><span class="params">(<span class="type">int</span> from, <span class="type">int</span> to, <span class="type">int</span> w)</span> </span>{</span><br><span class="line"> edges[++eidx] = (Edge){ head[from], to, w }, head[from] = eidx;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">Merge</span><span class="params">(<span class="type">int</span> x, <span class="type">int</span> y, <span class="type">const</span> LL& d)</span> </span>{</span><br><span class="line"> <span class="keyword">while</span> (rt0[x] > <span class="number">0</span> && rt1[y] > <span class="number">0</span>) {</span><br><span class="line"> Pli &t0 = Heap::val[rt0[x]], &t1 = Heap::val[rt1[y]];</span><br><span class="line"> <span class="keyword">if</span> (t<span class="number">0.f</span>irst + t<span class="number">1.f</span>irst - <span class="number">2</span> * d >= <span class="number">0</span>) <span class="keyword">break</span>;</span><br><span class="line"> <span class="type">int</span> s = <span class="built_in">min</span>(t<span class="number">0.</span>second, t<span class="number">1.</span>second);</span><br><span class="line"> ans += s * (t<span class="number">0.f</span>irst + t<span class="number">1.f</span>irst - <span class="number">2</span> * d);</span><br><span class="line"> t<span class="number">0.</span>second -= s, t<span class="number">1.</span>second -= s;</span><br><span class="line"> <span class="keyword">if</span> (t<span class="number">0.</span>second == <span class="number">0</span>) Heap::<span class="built_in">Pop</span>(rt0[x]);</span><br><span class="line"> <span class="keyword">if</span> (t<span class="number">1.</span>second == <span class="number">0</span>) Heap::<span class="built_in">Pop</span>(rt1[y]);</span><br><span class="line"> Heap::<span class="built_in">Psh</span>(rt0[x], <span class="built_in">Pli</span>(-t<span class="number">1.f</span>irst + <span class="number">2</span> * d, s));</span><br><span class="line"> Heap::<span class="built_in">Psh</span>(rt1[y], <span class="built_in">Pli</span>(-t<span class="number">0.f</span>irst + <span class="number">2</span> * d, s));</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">dfs</span><span class="params">(<span class="type">int</span> u, <span class="type">int</span> fa)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (X[u] > <span class="number">0</span>)</span><br><span class="line"> Heap::<span class="built_in">Psh</span>(rt0[u], <span class="built_in">Pli</span>(d[u], X[u]));</span><br><span class="line"> <span class="keyword">if</span> (Y[u] > <span class="number">0</span>)</span><br><span class="line"> Heap::<span class="built_in">Psh</span>(rt1[u], <span class="built_in">Pli</span>(d[u] - INFLL, Y[u])), ans += INFLL * Y[u];</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> v, i = head[u]; ~i; i = edges[i].nxt) {</span><br><span class="line"> <span class="keyword">if</span> ((v = edges[i].to) == fa) <span class="keyword">continue</span>;</span><br><span class="line"> d[v] = d[u] + edges[i].w, <span class="built_in">dfs</span>(v, u);</span><br><span class="line"> <span class="built_in">Merge</span>(u, v, d[u]), <span class="built_in">Merge</span>(v, u, d[u]);</span><br><span class="line"> rt0[u] = Heap::<span class="built_in">Mrg</span>(rt0[u], rt0[v]);</span><br><span class="line"> rt1[u] = Heap::<span class="built_in">Mrg</span>(rt1[u], rt1[v]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> Graph::<span class="built_in">init</span>();</span><br><span class="line"></span><br><span class="line"> <span class="built_in">read</span>(n);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> u, v, w, i = <span class="number">1</span>; i < n; ++i) {</span><br><span class="line"> <span class="built_in">read</span>(u), <span class="built_in">read</span>(v), <span class="built_in">read</span>(w);</span><br><span class="line"> Graph::<span class="built_in">AddEdge</span>(u, v, w), Graph::<span class="built_in">AddEdge</span>(v, u, w);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> v, i = <span class="number">1</span>; i <= n; ++i) {</span><br><span class="line"> <span class="built_in">read</span>(X[i]), <span class="built_in">read</span>(Y[i]);</span><br><span class="line"> v = <span class="built_in">min</span>(X[i], Y[i]), X[i] -= v, Y[i] -= v;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> Graph::<span class="built_in">dfs</span>(<span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%lld\n"</span>, ans);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li>陈江伦, <模拟费用流问题>, 2019.1.27.</li><li>boshi, <a href="https://www.mina.moe/archives/11762">模拟费用流的基本模型</a>.</li><li>mangoyang, <a href="https://www.cnblogs.com/mangoyang/p/11563486.html">模拟流的问题小结</a>.</li><li>litble, <a href="https://blog.csdn.net/litble/article/details/88410435">模拟费用流模型总结</a>.</li><li>200815147, <a href="https://blog.csdn.net/baidu_36797646/java/article/details/87071691">LOJ #2306「NOI2017」蔬菜 模拟费用流</a></li></ul><hr>]]></content>
<summary type="html"><hr>
<p>祝贺我又学了一个学不明白的东西 (</p>
<h2 id="综述"><a href="#综述" class="headerlink" title="综述"></a>综述</h2><p>模拟费用流, 大概是利用流的一些性质, 从而用数据结构高效模拟费用流.</p>
<p>基础理论和模型可以看看文末的参考资料, 这里只是记录我做过的一些题目.</p></summary>
<category term="笔记" scheme="https://depletedprism.github.io/categories/%E7%AC%94%E8%AE%B0/"/>
<category term="Graph" scheme="https://depletedprism.github.io/tags/Graph/"/>
<category term="Greedy" scheme="https://depletedprism.github.io/tags/Greedy/"/>
</entry>
<entry>
<title>BJOI 2018 简要题解</title>
<link href="https://depletedprism.github.io/sol/sx/BJOI-2018-sol/"/>
<id>https://depletedprism.github.io/sol/sx/BJOI-2018-sol/</id>
<published>2020-06-01T04:31:45.000Z</published>
<updated>2024-12-16T05:34:17.306Z</updated>
<content type="html"><![CDATA[<hr><p>这是 6 月份还在写省选题的悲惨故事.</p><span id="more"></span><p>BJOI 2018 Day 1 官方题解: <a href="http://qmqmqm.blog.uoj.ac/blog/3515">http://qmqmqm.blog.uoj.ac/blog/3515</a>.</p><h3 id="「BJOI2018」求和"><a href="#「BJOI2018」求和" class="headerlink" title="「BJOI2018」求和"></a>「BJOI2018」求和</h3><h4 id="题目链接"><a href="#题目链接" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://loj.ac/problem/2491">https://loj.ac/problem/2491</a></li></ul><h4 id="解题思路"><a href="#解题思路" class="headerlink" title="解题思路"></a>解题思路</h4><p>注意到只有查询操作, 那么直接对所有可能的 $k$ 计算当前点到根的累计点权和 $s_k$. 对于一次查询 $u$, $v$, 所求即为</p><script type="math/tex; mode=display">s_k(u) + s_k(v) - s_k(\mathrm{LCA}(u,\ v)) - s_k\big( \mathrm{pre}(\mathrm{LCA}(u,\ v)) \big)</script><p>直接求就好了. <del>原来难点在求 LCA 啊</del> (雾</p><p>时间复杂度 $O(nk + m \log n)$.</p><h4 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// LOJ #2491</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cctype></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstring></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> IO {</span><br><span class="line"> <span class="type">const</span> <span class="type">int</span> MAXSIZE = <span class="number">1</span> << <span class="number">18</span> | <span class="number">1</span>;</span><br><span class="line"> <span class="type">char</span> buf[MAXSIZE], *p1, *p2;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">Gc</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> p1 == p2 &&</span><br><span class="line"> (p2 = (p1 = buf) + <span class="built_in">fread</span>(buf, <span class="number">1</span>, MAXSIZE, stdin), p1 == p2)? EOF: *p1++;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">template</span><<span class="keyword">typename</span> T> <span class="keyword">inline</span> <span class="type">void</span> <span class="title">read</span><span class="params">(T& x)</span> </span>{</span><br><span class="line"> x = <span class="number">0</span>; <span class="type">int</span> f = <span class="number">0</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (!<span class="built_in">isdigit</span>(ch)) f |= ch == <span class="string">'-'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">isdigit</span>(ch)) x = x * <span class="number">10</span> + ch - <span class="string">'0'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">if</span> (f) x = -x;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">using</span> IO::read;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> LL;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">3e5</span> + <span class="number">5</span>, MAXK = <span class="number">51</span>, P = <span class="number">998244353</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, q;</span><br><span class="line"><span class="type">int</span> pre[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> Graph {</span><br><span class="line"> <span class="keyword">struct</span> <span class="title class_">Edge</span> { <span class="type">int</span> nxt, to; } edges[MAXN << <span class="number">1</span>];</span><br><span class="line"> <span class="type">int</span> head[MAXN], eidx;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">init</span><span class="params">()</span> </span>{ <span class="built_in">memset</span>(head, <span class="number">-1</span>, <span class="keyword">sizeof</span> head), eidx = <span class="number">1</span>; }</span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">AddEdge</span><span class="params">(<span class="type">int</span> from, <span class="type">int</span> to)</span> </span>{</span><br><span class="line"> edges[++eidx] = (Edge){ head[from], to }, head[from] = eidx;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> HLD {</span><br><span class="line"> <span class="keyword">using</span> <span class="keyword">namespace</span> Graph;</span><br><span class="line"> <span class="type">int</span> depth[MAXN], size[MAXN], son[MAXN], topfa[MAXN];</span><br><span class="line"> <span class="type">int</span> val[MAXK][MAXN], s[MAXK][MAXN];</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">dfs1</span><span class="params">(<span class="type">int</span> u, <span class="type">int</span> fa)</span> </span>{</span><br><span class="line"> depth[u] = depth[fa] + <span class="number">1</span>;</span><br><span class="line"> pre[u] = fa, size[u] = <span class="number">1</span>, son[u] = <span class="number">-1</span>;</span><br><span class="line"> val[<span class="number">0</span>][u] = <span class="number">1</span>, s[<span class="number">0</span>][u] = s[<span class="number">0</span>][fa] + <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i < MAXK; ++i) {</span><br><span class="line"> val[i][u] = <span class="number">1LL</span> * val[i - <span class="number">1</span>][u] * depth[u] % P;</span><br><span class="line"> s[i][u] = (s[i][fa] + val[i][u]) % P;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> v, i = head[u]; ~i; i = edges[i].nxt) {</span><br><span class="line"> <span class="keyword">if</span> ((v = edges[i].to) == fa) <span class="keyword">continue</span>;</span><br><span class="line"> <span class="built_in">dfs1</span>(v, u), size[u] += size[v];</span><br><span class="line"> <span class="keyword">if</span> (son[u] == <span class="number">-1</span> || size[v] > size[son[u]]) son[u] = v;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">dfs2</span><span class="params">(<span class="type">int</span> u, <span class="type">int</span> top)</span> </span>{</span><br><span class="line"> topfa[u] = top;</span><br><span class="line"> <span class="keyword">if</span> (~son[u]) <span class="built_in">dfs2</span>(son[u], top);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> v, i = head[u]; ~i; i = edges[i].nxt)</span><br><span class="line"> <span class="keyword">if</span> ((v = edges[i].to) != pre[u] && v != son[u]) <span class="built_in">dfs2</span>(v, v);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">solve</span><span class="params">(<span class="type">int</span> rt = <span class="number">1</span>)</span> </span>{</span><br><span class="line"> depth[<span class="number">0</span>] = <span class="number">-1</span>, <span class="built_in">dfs1</span>(rt, <span class="number">0</span>), <span class="built_in">dfs2</span>(rt, rt);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">LCA</span><span class="params">(<span class="type">int</span> u, <span class="type">int</span> v)</span> </span>{</span><br><span class="line"> <span class="keyword">while</span> (topfa[u] != topfa[v]) {</span><br><span class="line"> <span class="keyword">if</span> (depth[topfa[u]] < depth[topfa[v]]) <span class="built_in">swap</span>(u, v);</span><br><span class="line"> u = pre[topfa[u]];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> (depth[u] > depth[v])? v: u;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> Graph::<span class="built_in">init</span>();</span><br><span class="line"></span><br><span class="line"> <span class="built_in">read</span>(n);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> u, v, i = <span class="number">1</span>; i < n; ++i) {</span><br><span class="line"> <span class="built_in">read</span>(u), <span class="built_in">read</span>(v);</span><br><span class="line"> Graph::<span class="built_in">AddEdge</span>(u, v), Graph::<span class="built_in">AddEdge</span>(v, u);</span><br><span class="line"> }</span><br><span class="line"> HLD::<span class="built_in">solve</span>(<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">read</span>(q);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> u, v, k; q; --q) {</span><br><span class="line"> <span class="built_in">read</span>(u), <span class="built_in">read</span>(v), <span class="built_in">read</span>(k);</span><br><span class="line"> <span class="type">int</span> l = HLD::<span class="built_in">LCA</span>(u, v), *s = HLD::s[k];</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%lld\n"</span>, (((LL) s[u] + s[v] - s[l] - s[pre[l]]) % P + P) % P);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="「BJOI2018」二进制"><a href="#「BJOI2018」二进制" class="headerlink" title="「BJOI2018」二进制"></a>「BJOI2018」二进制</h3><h4 id="题目链接-1"><a href="#题目链接-1" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://loj.ac/problem/2492">https://loj.ac/problem/2492</a></li></ul><h4 id="解题思路-1"><a href="#解题思路-1" class="headerlink" title="解题思路"></a>解题思路</h4><p>考虑到重排操作, 那么某个区间是否可以组成 $3$ 的倍数和区间中 $0$ 和 $1$ 的个数有关.</p><p>记区间内 $0$ 的个数为 $s_0$, $1$ 的个数为 $s_1$, 先考虑哪些情况无法组成 $3$ 的倍数.</p><ol><li><p>$s_1$ 为 $1$, 其余位置都是 $0$.</p><p>此时无论如何重排, 所得结果都是 $2$ 的幂次, 不是 $3$ 的倍数.</p></li><li><p>$s_1$ 为奇数, 且 $s_0 < 2$.</p><p>逐位考虑二进制下的每一位 $1$, 单独拿出来在模 $3$ 意义下的值为 $1$ 或 $2$. 如果要构造出 $3$ 的倍数, 那么一定要将 $1$ 和 $2$ 两两配对. 也就可以得到, $s_1$ 为偶数时一定有解.</p><p>如果 $s_1$ 为奇数时, 若 $s_2 \ge 2$, 则可构造出 $(10101)_2 = (21)_{10}$, 其余 $0$ 放在高位, $1$ 放在低位, 从而组成 $3$ 的倍数. 而其余情况不存在类似的构造方案.</p></li></ol><p>那么我们可以用所有子区间的个数减去不合法的子区间个数来计算答案, 同时, 为了避免重复计算, 认为情况 1 中 $s_0 \ge 2$. 现在的问题在于如何统计无法重排为 $3$ 的倍数的子区间个数.</p><p>考虑 DP, 对于每个区间</p><p>设 $f_L(i)$, $i \in \{ 0, 1, 2 \}$ 分别表示强制包含该区间左端点的, 满足区间内 $s_1 = 1$, 且 $s_0$ 满足 $s_0 = 0$ / $s_0 = 1$ / $s_0 \ge 2$ 的子区间个数.</p><p>$g_L(i, j)$, $i,j \in \{ 0, 1 \}$ 表示强制包含该区间左端点的, 满足区间内 $s_0 = i$, $s_1$ 奇偶性为 $j$ 的子区间个数.</p><p>同理有 $f_R(i)$, $g_R(i, j)$. 转移则直接按照定义合并两个区间, 需要维护每个区间靠左连续 $0$ 个数, 以及靠右连续 $0$ 个数, 并统计跨过两个区间的答案.</p><p>注意到有修改操作, 那么用线段树维护转移即可. 时间复杂度 $O(m \log n)$.</p><p>硬要解释的话, 这道题可以算是序列上的动态 DP?</p><h4 id="代码实现-1"><a href="#代码实现-1" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// LOJ #2492</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cctype></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> IO {</span><br><span class="line"> <span class="type">const</span> <span class="type">int</span> MAXSIZE = <span class="number">1</span> << <span class="number">18</span> | <span class="number">1</span>;</span><br><span class="line"> <span class="type">char</span> buf[MAXSIZE], *p1, *p2;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">Gc</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> p1 == p2 &&</span><br><span class="line"> (p2 = (p1 = buf) + <span class="built_in">fread</span>(buf, <span class="number">1</span>, MAXSIZE, stdin), p1 == p2)? EOF: *p1++;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">template</span><<span class="keyword">typename</span> T> <span class="keyword">inline</span> <span class="type">void</span> <span class="title">read</span><span class="params">(T& x)</span> </span>{</span><br><span class="line"> x = <span class="number">0</span>; <span class="type">int</span> f = <span class="number">0</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (!<span class="built_in">isdigit</span>(ch)) f |= ch == <span class="string">'0'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">isdigit</span>(ch)) x = x * <span class="number">10</span> + ch - <span class="string">'0'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">if</span> (f) x = -x;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">using</span> IO::read;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> LL;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">1e5</span> + <span class="number">5</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> LL <span class="title">binom2</span><span class="params">(<span class="type">int</span> n)</span> </span>{ <span class="keyword">return</span> <span class="number">1LL</span> * n * (n - <span class="number">1</span>) / <span class="number">2</span>; }</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, q;</span><br><span class="line"><span class="type">int</span> A[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> lc (nd << 1)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> rc (nd << 1 | 1)</span></span><br><span class="line"><span class="keyword">namespace</span> SGT {</span><br><span class="line"> <span class="keyword">struct</span> <span class="title class_">Node</span> {</span><br><span class="line"> <span class="type">int</span> s, s0, s1, l0, r0;</span><br><span class="line"> LL fl[<span class="number">3</span>], fr[<span class="number">3</span>], gl[<span class="number">2</span>][<span class="number">2</span>], gr[<span class="number">2</span>][<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line"> <span class="built_in">Node</span>() { <span class="built_in">clear</span>(); }</span><br><span class="line"> <span class="built_in">Node</span>(<span class="type">const</span> <span class="type">int</span>& v) {</span><br><span class="line"> <span class="built_in">clear</span>();</span><br><span class="line"> <span class="keyword">if</span> (v) fl[<span class="number">0</span>] = fr[<span class="number">0</span>] = gl[<span class="number">0</span>][<span class="number">1</span>] = gr[<span class="number">0</span>][<span class="number">1</span>] = s = s1 = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">else</span> gl[<span class="number">1</span>][<span class="number">0</span>] = gr[<span class="number">1</span>][<span class="number">0</span>] = s0 = l0 = r0 = <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">clear</span><span class="params">()</span> </span>{</span><br><span class="line"> s = s0 = s1 = l0 = r0 = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < <span class="number">3</span>; ++i) fl[i] = fr[i] = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < <span class="number">2</span>; ++i)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j < <span class="number">2</span>; ++j) gl[i][j] = gr[i][j] = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> } dat[MAXN << <span class="number">2</span>];</span><br><span class="line"></span><br><span class="line"> Node <span class="keyword">operator</span> + (<span class="type">const</span> Node& A, <span class="type">const</span> Node& B) {</span><br><span class="line"> Node ret;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < <span class="number">3</span>; ++i) {</span><br><span class="line"> ret.fl[i] += A.fl[i], ret.fr[i] += B.fr[i];</span><br><span class="line"> <span class="keyword">if</span> (A.s1 == <span class="number">0</span>) ret.fl[<span class="built_in">min</span>(<span class="number">2</span>, i + A.s0)] += B.fl[i];</span><br><span class="line"> <span class="keyword">if</span> (B.s1 == <span class="number">0</span>) ret.fr[<span class="built_in">min</span>(<span class="number">2</span>, i + B.s0)] += A.fr[i];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (A.s1 == <span class="number">1</span> && B.l0 > <span class="number">0</span>)</span><br><span class="line"> ++ret.fl[<span class="built_in">min</span>(<span class="number">2</span>, A.s0 + B.l0)], ret.fl[<span class="number">2</span>] += B.l0 - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">if</span> (B.s1 == <span class="number">1</span> && A.r0 > <span class="number">0</span>)</span><br><span class="line"> ++ret.fr[<span class="built_in">min</span>(<span class="number">2</span>, B.s0 + A.r0)], ret.fr[<span class="number">2</span>] += A.r0 - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < <span class="number">2</span>; ++i)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j < <span class="number">2</span>; ++j) {</span><br><span class="line"> ret.gl[i][j] += A.gl[i][j], ret.gr[i][j] += B.gr[i][j];</span><br><span class="line"> <span class="keyword">if</span> (i >= A.s0) ret.gl[i][j] += B.gl[i - A.s0][j ^ (A.s1 & <span class="number">1</span>)];</span><br><span class="line"> <span class="keyword">if</span> (i >= B.s0) ret.gr[i][j] += A.gr[i - B.s0][j ^ (B.s1 & <span class="number">1</span>)];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ret.l0 = (A.s1 == <span class="number">0</span>)? A.l0 + B.l0: A.l0;</span><br><span class="line"> ret.r0 = (B.s1 == <span class="number">0</span>)? B.r0 + A.r0: B.r0;</span><br><span class="line"> ret.s1 = A.s1 + B.s1, ret.s0 = A.s0 + B.s0, ret.s = A.s + B.s;</span><br><span class="line"></span><br><span class="line"> ret.s += A.gr[<span class="number">0</span>][<span class="number">0</span>] * (B.gl[<span class="number">0</span>][<span class="number">1</span>] + B.gl[<span class="number">1</span>][<span class="number">1</span>]);</span><br><span class="line"> ret.s += A.gr[<span class="number">0</span>][<span class="number">1</span>] * (B.gl[<span class="number">0</span>][<span class="number">0</span>] + B.gl[<span class="number">1</span>][<span class="number">0</span>]);</span><br><span class="line"> ret.s += A.gr[<span class="number">1</span>][<span class="number">0</span>] * B.gl[<span class="number">0</span>][<span class="number">1</span>] + A.gr[<span class="number">1</span>][<span class="number">1</span>] * B.gl[<span class="number">0</span>][<span class="number">0</span>];</span><br><span class="line"> <span class="keyword">if</span> (A.r0 > <span class="number">0</span>)</span><br><span class="line"> ret.s += (A.r0 - <span class="number">1</span>) * B.fl[<span class="number">0</span>] + A.r0 * (B.fl[<span class="number">1</span>] + B.fl[<span class="number">2</span>]);</span><br><span class="line"> <span class="keyword">if</span> (B.l0 > <span class="number">0</span>)</span><br><span class="line"> ret.s += (B.l0 - <span class="number">1</span>) * A.fr[<span class="number">0</span>] + B.l0 * (A.fr[<span class="number">1</span>] + A.fr[<span class="number">2</span>]);</span><br><span class="line"> <span class="keyword">return</span> ret;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">maintain</span><span class="params">(<span class="type">int</span> nd)</span> </span>{ dat[nd] = dat[lc] + dat[rc]; }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">build</span><span class="params">(<span class="type">int</span> nd, <span class="type">int</span> L, <span class="type">int</span> R)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (L == R) <span class="keyword">return</span> <span class="built_in">void</span>( dat[nd] = A[L] );</span><br><span class="line"> <span class="type">int</span> Mid = (L + R) / <span class="number">2</span>;</span><br><span class="line"> <span class="built_in">build</span>(lc, L, Mid), <span class="built_in">build</span>(rc, Mid + <span class="number">1</span>, R);</span><br><span class="line"> <span class="built_in">maintain</span>(nd);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">Mdy</span><span class="params">(<span class="type">int</span> nd, <span class="type">int</span> L, <span class="type">int</span> R, <span class="type">const</span> <span class="type">int</span>& p, <span class="type">const</span> <span class="type">int</span>& v)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (L == R) <span class="keyword">return</span> <span class="built_in">void</span>( dat[nd] = <span class="built_in">Node</span>(v) );</span><br><span class="line"> <span class="type">int</span> Mid = (L + R) / <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">if</span> (p <= Mid) <span class="built_in">Mdy</span>(lc, L, Mid, p, v); <span class="keyword">else</span> <span class="built_in">Mdy</span>(rc, Mid + <span class="number">1</span>, R, p, v);</span><br><span class="line"> <span class="built_in">maintain</span>(nd);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function">Node <span class="title">Qry</span><span class="params">(<span class="type">int</span> nd, <span class="type">int</span> L, <span class="type">int</span> R, <span class="type">const</span> <span class="type">int</span>& opL, <span class="type">const</span> <span class="type">int</span>& opR)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (opL <= L && R <= opR) <span class="keyword">return</span> dat[nd];</span><br><span class="line"> <span class="type">int</span> Mid = (L + R) / <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">if</span> (opR <= Mid) <span class="keyword">return</span> <span class="built_in">Qry</span>(lc, L, Mid, opL, opR);</span><br><span class="line"> <span class="keyword">if</span> (opL > Mid) <span class="keyword">return</span> <span class="built_in">Qry</span>(rc, Mid + <span class="number">1</span>, R, opL, opR);</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Qry</span>(lc, L, Mid, opL, opR) + <span class="built_in">Qry</span>(rc, Mid + <span class="number">1</span>, R, opL, opR);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="meta">#<span class="keyword">undef</span> lc</span></span><br><span class="line"><span class="meta">#<span class="keyword">undef</span> rc</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="built_in">read</span>(n);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) <span class="built_in">read</span>(A[i]);</span><br><span class="line"></span><br><span class="line"> SGT::<span class="built_in">build</span>(<span class="number">1</span>, <span class="number">1</span>, n);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">read</span>(q);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> opt, L, R; q; --q) {</span><br><span class="line"> <span class="built_in">read</span>(opt), <span class="built_in">read</span>(L);</span><br><span class="line"> <span class="keyword">switch</span> (opt) {</span><br><span class="line"> <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line"> A[L] ^= <span class="number">1</span>, SGT::<span class="built_in">Mdy</span>(<span class="number">1</span>, <span class="number">1</span>, n, L, A[L]);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">2</span>:</span><br><span class="line"> <span class="built_in">read</span>(R);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%lld\n"</span>, <span class="built_in">binom2</span>(R - L + <span class="number">2</span>) - SGT::<span class="built_in">Qry</span>(<span class="number">1</span>, <span class="number">1</span>, n, L, R).s);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">default</span>: <span class="built_in">fprintf</span>(stderr, <span class="string">"ERR\n"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="「BJOI2018」染色"><a href="#「BJOI2018」染色" class="headerlink" title="「BJOI2018」染色"></a>「BJOI2018」染色</h3><h4 id="题目链接-2"><a href="#题目链接-2" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://loj.ac/problem/2493">https://loj.ac/problem/2493</a></li></ul><h4 id="解题思路-2"><a href="#解题思路-2" class="headerlink" title="解题思路"></a>解题思路</h4><p>容易发现, 对于不是二分图的无向图, 其答案一定为 <code>NO</code>. 此后只需讨论二分图, 也就是只存在偶环的图.</p><p>但不是所有二分图答案都为 <code>YES</code>. 例如样例 1 中的完全二分图 $K_{3, 3}$.</p><p>对于有一个公共点的两个偶环, 存在一种构造方案使其一定不合法. 这也就意味着, 如果存在度数 $> 3$ 的点, 则答案为 <code>NO</code>. 同时, 度数为 $1$ 的点并不影响答案, 可直接删去.</p><p>图中不同的连通块之间互不影响. 现在依次考虑每一个连通块, 剩余的情况有</p><ol><li><p>不同其他环有交点的偶环.</p><p>无论给定何种颜色集合, pupil 都可构造出颜色交替的合法方案.</p></li><li><p>存在两个度数为 $3$ 的点.</p><p>此时两个度数为 $3$ 的点之间三条不相交的路径. 当且仅当这三条路径长满足 “2 - 2 - 偶数” 的形式时 pupil 一定内构造出合法方案.</p></li></ol><p>详尽具体的证明可参考 <a href="https://qmqmqm.blog.uoj.ac/blog/3515">官方题解</a>, 或是 <a href="https://blog.csdn.net/zxyoi_dreamer/article/details/88255198">zxyoi 的题解</a>.</p><p><del><em>其实证明也就是给出某种方案将不合法的情况卡掉…</em></del></p><p>实现则直接根据以上性质判断. 时间复杂度 $O(n \log n + m)$, 可能会因实现不同而有不同 (</p><h4 id="代码实现-2"><a href="#代码实现-2" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// LOJ #2493</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cctype></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><vector></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstring></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> IO {</span><br><span class="line"> <span class="type">const</span> <span class="type">int</span> MAXSIZE = <span class="number">1</span> << <span class="number">18</span> | <span class="number">1</span>;</span><br><span class="line"> <span class="type">char</span> buf[MAXSIZE], *p1, *p2;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">Gc</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> p1 == p2 &&</span><br><span class="line"> (p2 = (p1 = buf) + <span class="built_in">fread</span>(buf, <span class="number">1</span>, MAXSIZE, stdin), p1 == p2)? EOF: *p1++;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">template</span><<span class="keyword">typename</span> T> <span class="keyword">inline</span> <span class="type">void</span> <span class="title">read</span><span class="params">(T& x)</span> </span>{</span><br><span class="line"> x = <span class="number">0</span>; <span class="type">int</span> f = <span class="number">0</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (!<span class="built_in">isdigit</span>(ch)) f |= ch == <span class="string">'-'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">isdigit</span>(ch)) x = x * <span class="number">10</span> + ch - <span class="string">'0'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">if</span> (f) x = -x;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">using</span> IO::read;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">1e4</span> + <span class="number">5</span>, MAXM = <span class="number">2e4</span> + <span class="number">5</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, m;</span><br><span class="line">vector<<span class="type">int</span>> G[MAXN];</span><br><span class="line"><span class="type">int</span> deg[MAXN]; <span class="type">bool</span> vis[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> DSU {</span><br><span class="line"> <span class="type">int</span> fa[MAXN];</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">init</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) fa[i] = i;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">findfa</span><span class="params">(<span class="type">int</span> u)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (fa[u] == u)? u: fa[u] = <span class="built_in">findfa</span>(fa[u]);</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">join</span><span class="params">(<span class="type">int</span> u, <span class="type">int</span> v)</span> </span>{</span><br><span class="line"> u = <span class="built_in">findfa</span>(u), v = <span class="built_in">findfa</span>(v);</span><br><span class="line"> <span class="keyword">if</span> (u != v) fa[u] = v;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> Graph {</span><br><span class="line"> <span class="keyword">struct</span> <span class="title class_">Edge</span> { <span class="type">int</span> nxt, to; } edges[MAXM << <span class="number">1</span>];</span><br><span class="line"> <span class="type">int</span> head[MAXN], eidx;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">init</span><span class="params">()</span> </span>{</span><br><span class="line"> eidx = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i)</span><br><span class="line"> G[i].<span class="built_in">clear</span>(), deg[i] = <span class="number">0</span>, head[i] = <span class="number">-1</span>, vis[i] = <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">AddEdge</span><span class="params">(<span class="type">int</span> from, <span class="type">int</span> to)</span> </span>{</span><br><span class="line"> edges[++eidx] = (Edge){ head[from], to }, head[from] = eidx;</span><br><span class="line"> ++deg[to];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">Toposort</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="type">static</span> <span class="type">int</span> Q[MAXN], h, t;</span><br><span class="line"> Q[h = <span class="number">1</span>] = t = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> u = <span class="number">1</span>; u <= n; ++u)</span><br><span class="line"> <span class="keyword">if</span> (deg[u] == <span class="number">1</span>) vis[u] = <span class="literal">true</span>, Q[++t] = u;</span><br><span class="line"> <span class="keyword">while</span> (h <= t) {</span><br><span class="line"> <span class="type">int</span> u = Q[h++];</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> v, i = head[u]; ~i; i = edges[i].nxt) {</span><br><span class="line"> <span class="keyword">if</span> (vis[v = edges[i].to]) <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">if</span> ((--deg[v]) == <span class="number">1</span>) vis[v] = <span class="literal">true</span>, Q[++t] = v;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">2</span>; i <= eidx; i += <span class="number">2</span>) {</span><br><span class="line"> <span class="type">int</span> u = edges[i ^ <span class="number">1</span>].to, v = edges[i].to;</span><br><span class="line"> <span class="keyword">if</span> (!vis[u] && !vis[v]) DSU::<span class="built_in">join</span>(u, v);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">bool</span> <span class="title">check</span><span class="params">()</span> </span>{</span><br><span class="line"> Graph::<span class="built_in">Toposort</span>();</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> u = <span class="number">1</span>; u <= n; ++u)</span><br><span class="line"> G[DSU::<span class="built_in">findfa</span>(u)].<span class="built_in">push_back</span>(u);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> u = <span class="number">1</span>; u <= n; ++u) {</span><br><span class="line"> <span class="keyword">if</span> (DSU::fa[u] != u || G[u].<span class="built_in">size</span>() <= <span class="number">1</span>) <span class="keyword">continue</span>;</span><br><span class="line"> <span class="type">int</span> c = <span class="number">0</span>, x = <span class="number">-1</span>, y = <span class="number">-1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">const</span> <span class="type">int</span>& v: G[u]) {</span><br><span class="line"> <span class="keyword">if</span> (deg[v] > <span class="number">3</span>) <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> <span class="keyword">if</span> (deg[v] == <span class="number">3</span>) {</span><br><span class="line"> <span class="keyword">if</span> (++c == <span class="number">1</span>) x = v; <span class="keyword">else</span> y = v;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (c == <span class="number">1</span> || c > <span class="number">2</span>) <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> <span class="keyword">if</span> (c == <span class="number">0</span> && G[u].<span class="built_in">size</span>() % <span class="number">2</span> == <span class="number">1</span>) <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> <span class="keyword">if</span> (c != <span class="number">2</span>) <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">if</span> (G[u].<span class="built_in">size</span>() % <span class="number">2</span> == <span class="number">0</span>) <span class="keyword">return</span> <span class="literal">false</span>; <span class="comment">// 2 - 2 - Even</span></span><br><span class="line"> <span class="type">int</span> e = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">const</span> <span class="type">int</span>& v: G[u]) <span class="keyword">if</span> (v != x && v != y) {</span><br><span class="line"> <span class="type">int</span> l = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> w, i = Graph::head[v]; ~i; i = Graph::edges[i].nxt)</span><br><span class="line"> <span class="keyword">if</span> ((w = Graph::edges[i].to) == x || w == y) ++l;</span><br><span class="line"> <span class="keyword">if</span> (l == <span class="number">2</span>) ++e;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (e < <span class="number">2</span>) <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="type">int</span> Ti; <span class="built_in">read</span>(Ti);</span><br><span class="line"> <span class="keyword">while</span> (Ti--) {</span><br><span class="line"> <span class="built_in">read</span>(n), <span class="built_in">read</span>(m);</span><br><span class="line"></span><br><span class="line"> Graph::<span class="built_in">init</span>(), DSU::<span class="built_in">init</span>();</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> u, v, i = <span class="number">1</span>; i <= m; ++i) {</span><br><span class="line"> <span class="built_in">read</span>(u), <span class="built_in">read</span>(v);</span><br><span class="line"> Graph::<span class="built_in">AddEdge</span>(u, v), Graph::<span class="built_in">AddEdge</span>(v, u);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">puts</span>(<span class="built_in">check</span>()? <span class="string">"YES"</span>: <span class="string">"NO"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="「BJOI2018」双人猜数游戏"><a href="#「BJOI2018」双人猜数游戏" class="headerlink" title="「BJOI2018」双人猜数游戏"></a>「BJOI2018」双人猜数游戏</h3><p>不明真相的吃瓜群众直呼内行.</p><h4 id="题目链接-3"><a href="#题目链接-3" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://loj.ac/problem/2511">https://loj.ac/problem/2511</a></li></ul><h4 id="解题思路-3"><a href="#解题思路-3" class="headerlink" title="解题思路"></a>解题思路</h4><p>似乎更像是一道传统题?</p><p>首先可以观察到, Bob 和 Alice 确定答案的依据为, 自己已知的答案集合时候在对手看来是否是唯一的. 每次对手回答知道 / 不知道, 都能在自己的答案集合中排除一些结果. 剩余结果唯一时则得到了答案.</p><p>可能有些抽象, 对于样例 1 的模拟可参考 <a href="https://0x131cc05.github.io/2019/04/07/BJOI2018-%E5%8F%8C%E4%BA%BA%E7%8C%9C%E6%95%B0%E6%B8%B8%E6%88%8F/">An_Account 的题解</a>.</p><p>考虑用 DP 模拟这个过程. 设 $f(i, m, n)$ 表示当前在第 $i$ 轮, 已经说出 $i - 1$ 次不知道时, $(m, n)$ 是否能确定为答案. 那么最终答案需满足 $f(t + 1, m, n)$ 能够确定为答案.</p><p>显然有转移 $f(i, m, n) = f(i - 2, m, n)$, 表示之前能够确定, 再下一回合仍可确定.</p><p>对于 Bob, 转移则直接枚举 $m + n$ 的合法整数分解, 判断是否唯一存在恰好一组 $(x, y)$ 满足 $x + y = m + n$ 且 $f(i - 1, x, y)$ 为假, 也就是上一次猜测中并不能确定. Alice 则类似.</p><p>还有一种边界情况. 注意到题目要求 “ 一共说了 $t$ 次 ‘不知道’ 以后两个人都知道 $m$ 和 $n$ 是多少了”, 要排除一个人知道, 但另一个人却不知道的情况. 再进行一次类似的转移, 要求其在第 $t + 1$ 轮猜出, 且第 $t - 1$ 轮并不确定.</p><p>答案中 $m$, $n$ 上界并未给定, 但所有数据都可以在较短的时间内求出.</p><h4 id="代码实现-3"><a href="#代码实现-3" class="headerlink" title="代码实现"></a>代码实现</h4><p>可以适当调整 <code>MAXM</code> 或 <code>MAXN</code> 可以在正确性和时间内平衡. 有时候会 <code>RE</code>, 不用管就是了 (</p><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// LOJ #2511</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXM = <span class="number">1e4</span> + <span class="number">5</span>, MAXN = <span class="number">5e2</span> + <span class="number">5</span>, MAXT = <span class="number">20</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> s, t;</span><br><span class="line"><span class="type">char</span> First[MAXT];</span><br><span class="line"></span><br><span class="line"><span class="type">bool</span> f[MAXT][MAXM][MAXM];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">bool</span> <span class="title">check1</span><span class="params">(<span class="type">int</span> m, <span class="type">int</span> n, <span class="type">const</span> <span class="type">int</span>& i)</span> </span>{ <span class="comment">// Bob</span></span><br><span class="line"> <span class="type">int</span> cnt = <span class="number">0</span>, ax = <span class="number">-1</span>, ay = <span class="number">-1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> x = s; <span class="number">2</span> * x <= m + n; ++x) {</span><br><span class="line"> <span class="type">int</span> y = m + n - x;</span><br><span class="line"> <span class="keyword">if</span> (i == <span class="number">1</span> || !f[i - <span class="number">1</span>][x][y]) {</span><br><span class="line"> ++cnt, ax = x, ay = y;</span><br><span class="line"> <span class="keyword">if</span> (cnt == <span class="number">2</span>) <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> cnt == <span class="number">1</span> && ax == m && ay == n;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">bool</span> <span class="title">check2</span><span class="params">(<span class="type">int</span> m, <span class="type">int</span> n, <span class="type">const</span> <span class="type">int</span>& i)</span> </span>{ <span class="comment">// Alice</span></span><br><span class="line"> <span class="type">int</span> cnt = <span class="number">0</span>, ax = <span class="number">-1</span>, ay = <span class="number">-1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> x = s; x * x <= m * n; ++x) <span class="keyword">if</span> (m * n % x == <span class="number">0</span>) {</span><br><span class="line"> <span class="type">int</span> y = m * n / x;</span><br><span class="line"> <span class="keyword">if</span> (i == <span class="number">1</span> || !f[i - <span class="number">1</span>][x][y]) {</span><br><span class="line"> ++cnt, ax = x, ay = y;</span><br><span class="line"> <span class="keyword">if</span> (cnt == <span class="number">2</span>) <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> cnt == <span class="number">1</span> && ax == m && ay == n;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">bool</span> <span class="title">check1</span><span class="params">(<span class="type">int</span> m, <span class="type">int</span> n)</span> </span>{</span><br><span class="line"> <span class="type">int</span> cnt = <span class="number">0</span>, ax = <span class="number">-1</span>, ay = <span class="number">-1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> x = s; <span class="number">2</span> * x <= m + n; ++x) {</span><br><span class="line"> <span class="type">int</span> y = m + n - x;</span><br><span class="line"> <span class="keyword">if</span> (f[t + <span class="number">1</span>][x][y] && !f[t - <span class="number">1</span>][x][y]) {</span><br><span class="line"> ++cnt, ax = x, ay = y;</span><br><span class="line"> <span class="keyword">if</span> (cnt == <span class="number">2</span>) <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> cnt == <span class="number">1</span> && ax == m && ay == n;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">bool</span> <span class="title">check2</span><span class="params">(<span class="type">int</span> m, <span class="type">int</span> n)</span> </span>{</span><br><span class="line"> <span class="type">int</span> cnt = <span class="number">0</span>, ax = <span class="number">-1</span>, ay = <span class="number">-1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> x = s; x * x <= m * n; ++x) <span class="keyword">if</span> (m * n % x == <span class="number">0</span>) {</span><br><span class="line"> <span class="type">int</span> y = m * n / x;</span><br><span class="line"> <span class="keyword">if</span> (f[t + <span class="number">1</span>][x][y] && !f[t - <span class="number">1</span>][x][y]) {</span><br><span class="line"> ++cnt, ax = x, ay = y;</span><br><span class="line"> <span class="keyword">if</span> (cnt == <span class="number">2</span>) <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> cnt == <span class="number">1</span> && ax == m && ay == n;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%s%d"</span>, &s, First, &t);</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> fst = (First[<span class="number">0</span>] == <span class="string">'B'</span>); <span class="comment">// Alice: 0, Bob: 1</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= t + <span class="number">1</span>; ++i)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> m = s; <span class="number">2</span> * m < MAXN; ++m)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> n = m; n < MAXN; ++n) {</span><br><span class="line"> <span class="keyword">if</span> (i > <span class="number">1</span>) f[i][m][n] |= f[i - <span class="number">2</span>][m][n];</span><br><span class="line"> f[i][m][n] |= ((i & <span class="number">1</span>) ^ fst)? <span class="built_in">check2</span>(m, n, i): <span class="built_in">check1</span>(m, n, i);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// for (int sum = 2 * s; ; ++sum)</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> sum = <span class="number">2</span> * s; sum < MAXM; ++sum)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> m = s; <span class="number">2</span> * m <= sum; ++m) {</span><br><span class="line"> <span class="type">int</span> n = sum - m;</span><br><span class="line"> <span class="keyword">if</span> (f[t + <span class="number">1</span>][m][n] && !(f[t][m][n] || f[t - <span class="number">1</span>][m][n])) {</span><br><span class="line"> <span class="keyword">if</span> ((t & <span class="number">1</span>) ^ fst) {</span><br><span class="line"> <span class="keyword">if</span> (!<span class="built_in">check2</span>(m, n)) <span class="keyword">continue</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">if</span> (!<span class="built_in">check1</span>(m, n)) <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">printf</span>(<span class="string">"%d %d\n"</span>, m, n), <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">puts</span>(<span class="string">"-1 -1"</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="「BJOI2018」链上二次求和"><a href="#「BJOI2018」链上二次求和" class="headerlink" title="「BJOI2018」链上二次求和"></a>「BJOI2018」链上二次求和</h3><h4 id="题目链接-4"><a href="#题目链接-4" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://loj.ac/problem/2512">https://loj.ac/problem/2512</a></li></ul><h4 id="解题思路-4"><a href="#解题思路-4" class="headerlink" title="解题思路"></a>解题思路</h4><p>设 $s_i$ 表示 $a_i$ 的前缀和, $f_i$ 表示 $s_i$ 的前缀和.</p><p>对于每次询问, 其答案为</p><script type="math/tex; mode=display">\sum_{i = L} ^ R \sum_{j = i} ^ n ( s_j - s_{j - i} )= \sum_{i = L} ^ R (f_n - f_{i - 1} - f_{n - i})</script><p>利用线段树维护 $f_i$ 部分和即可在 $O(\log n)$ 的时间复杂度内计算答案.</p><p>关键在于每次修改对 $f_i$ 的影响. 设当前修改区间为 $[L, R]$, 增加值为 $d$.</p><p>对于每个位置 $i$, 其被覆盖次数为公差为 $1$ 的等差数列, 令 $s(n) = \sum\limits_{k = 1} ^ n k = \frac{1}{2} n (n + 1)$. 整理可得</p><script type="math/tex; mode=display">f_i = \begin{cases}d \cdot s(i - L + 1) & i \in [L, R] \\d \cdot s(R - L + 1) + d (i - R) (R - L + 1) & i \in (R, n]\end{cases}</script><p>上式可表示为 $a i ^ 2 + bi + c$ 的形式. 利用线段树维护标记 $a$, $b$, $c$ 更新 $f_i$ 的部分和即可.</p><p>时间复杂度 $O(m \log n)$, 常数较大.</p><p>注意操作 1 中并未限定 $u \le v$…</p><h4 id="代码实现-4"><a href="#代码实现-4" class="headerlink" title="代码实现"></a>代码实现</h4><p>苟活在现代编译器的底层优化之下…</p><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// LOJ #2512</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cctype></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdlib></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> IO {</span><br><span class="line"> <span class="type">const</span> <span class="type">int</span> MAXSIZE = <span class="number">1</span> << <span class="number">18</span> | <span class="number">1</span>;</span><br><span class="line"> <span class="type">char</span> buf[MAXSIZE], *p1, *p2;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">Gc</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> p1 == p2 &&</span><br><span class="line"> (p2 = (p1 = buf) + <span class="built_in">fread</span>(buf, <span class="number">1</span>, MAXSIZE, stdin), p1 == p2)? EOF: *p1++;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">template</span><<span class="keyword">typename</span> T> <span class="keyword">inline</span> <span class="type">void</span> <span class="title">read</span><span class="params">(T& x)</span> </span>{</span><br><span class="line"> x = <span class="number">0</span>; <span class="type">int</span> f = <span class="number">0</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (!<span class="built_in">isdigit</span>(ch)) f |= ch == <span class="string">'-'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">isdigit</span>(ch)) x = x * <span class="number">10</span> + ch - <span class="string">'0'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">if</span> (f) x = -x;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">using</span> IO::read;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> LL;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">2e5</span> + <span class="number">5</span>, P = <span class="number">1e9</span> + <span class="number">7</span>, iv2 = <span class="number">500000004</span>, iv6 = <span class="number">166666668</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">Fix</span><span class="params">(<span class="type">int</span> a)</span> </span>{ <span class="keyword">return</span> a + (a >> <span class="number">31</span> & P); }</span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">pls</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span> </span>{ <span class="keyword">return</span> <span class="built_in">Fix</span>(a + b - P); }</span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">mns</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span> </span>{ <span class="keyword">return</span> <span class="built_in">Fix</span>(a - b); }</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Z</span> {</span><br><span class="line"> <span class="type">int</span> x;</span><br><span class="line"></span><br><span class="line"> <span class="built_in">Z</span>() { x = <span class="number">0</span>; }</span><br><span class="line"> <span class="built_in">Z</span>(<span class="type">int</span> _x): <span class="built_in">x</span>(_x) { }</span><br><span class="line"></span><br><span class="line"> Z <span class="keyword">operator</span> + (<span class="type">const</span> Z& rhs) <span class="type">const</span> { <span class="keyword">return</span> <span class="built_in">Z</span>(<span class="built_in">pls</span>(x, rhs.x)); }</span><br><span class="line"> Z <span class="keyword">operator</span> - (<span class="type">const</span> Z& rhs) <span class="type">const</span> { <span class="keyword">return</span> <span class="built_in">Z</span>(<span class="built_in">mns</span>(x, rhs.x)); }</span><br><span class="line"> Z <span class="keyword">operator</span> * (<span class="type">const</span> Z& rhs) <span class="type">const</span> { <span class="keyword">return</span> <span class="built_in">Z</span>(<span class="number">1LL</span> * x * rhs.x % P); }</span><br><span class="line"> Z <span class="keyword">operator</span> / (<span class="type">const</span> <span class="type">int</span>& rhs) <span class="type">const</span> {</span><br><span class="line"> <span class="keyword">if</span> (rhs == <span class="number">2</span>) <span class="keyword">return</span> *<span class="keyword">this</span> * <span class="built_in">Z</span>(iv2);</span><br><span class="line"> <span class="keyword">if</span> (rhs == <span class="number">6</span>) <span class="keyword">return</span> *<span class="keyword">this</span> * <span class="built_in">Z</span>(iv6);</span><br><span class="line"> <span class="built_in">abort</span>();</span><br><span class="line"> }</span><br><span class="line"> Z <span class="keyword">operator</span> += (<span class="type">const</span> Z& rhs) { <span class="keyword">return</span> *<span class="keyword">this</span> = *<span class="keyword">this</span> + rhs; }</span><br><span class="line"> Z <span class="keyword">operator</span> -= (<span class="type">const</span> Z& rhs) { <span class="keyword">return</span> *<span class="keyword">this</span> = *<span class="keyword">this</span> - rhs; }</span><br><span class="line"> <span class="type">bool</span> <span class="keyword">operator</span> < (<span class="type">const</span> Z& rhs) <span class="type">const</span> { <span class="keyword">return</span> x < rhs.x; }</span><br><span class="line"> <span class="type">bool</span> <span class="keyword">operator</span> > (<span class="type">const</span> Z& rhs) <span class="type">const</span> { <span class="keyword">return</span> rhs < *<span class="keyword">this</span>; }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> Z <span class="title">s0</span><span class="params">(Z L, Z R)</span> </span>{ <span class="keyword">return</span> R - L + <span class="number">1</span>; };</span><br><span class="line"><span class="function"><span class="keyword">inline</span> Z <span class="title">s1</span><span class="params">(Z n)</span> </span>{ <span class="keyword">return</span> (n > <span class="number">0</span>)? n * (n + <span class="number">1</span>) / <span class="number">2</span>: <span class="number">0</span>; }</span><br><span class="line"><span class="function"><span class="keyword">inline</span> Z <span class="title">s1</span><span class="params">(Z L, Z R)</span> </span>{ <span class="keyword">return</span> <span class="built_in">s1</span>(R) - <span class="built_in">s1</span>(L - <span class="number">1</span>); }</span><br><span class="line"><span class="function"><span class="keyword">inline</span> Z <span class="title">s2</span><span class="params">(Z n)</span> </span>{ <span class="keyword">return</span> (n > <span class="number">0</span>)? n * (n + <span class="number">1</span>) * (n * <span class="number">2</span> + <span class="number">1</span>) / <span class="number">6</span>: <span class="number">0</span>; }</span><br><span class="line"><span class="function"><span class="keyword">inline</span> Z <span class="title">s2</span><span class="params">(Z L, Z R)</span> </span>{ <span class="keyword">return</span> <span class="built_in">s2</span>(R) - <span class="built_in">s2</span>(L - <span class="number">1</span>); }</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, q;</span><br><span class="line"><span class="type">int</span> A[MAXN]; Z f[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> lc (nd << 1)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> rc (nd << 1 | 1)</span></span><br><span class="line"><span class="keyword">namespace</span> SGT {</span><br><span class="line"> Z s[MAXN << <span class="number">2</span>], ta[MAXN << <span class="number">2</span>], tb[MAXN << <span class="number">2</span>], tc[MAXN << <span class="number">2</span>];</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">maintain</span><span class="params">(<span class="type">int</span> nd)</span> </span>{ s[nd] = s[lc] + s[rc]; }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">push</span><span class="params">(<span class="type">int</span> nd, <span class="type">int</span> L, <span class="type">int</span> R, Z va, Z vb, Z vc)</span> </span>{</span><br><span class="line"> ta[nd] += va, tb[nd] += vb, tc[nd] += vc;</span><br><span class="line"> s[nd] += <span class="built_in">s2</span>(L, R) * va + <span class="built_in">s1</span>(L, R) * vb + <span class="built_in">s0</span>(L, R) * vc;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">pushdown</span><span class="params">(<span class="type">int</span> nd, <span class="type">int</span> L, <span class="type">int</span> R)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (ta[nd] > <span class="number">0</span> || tb[nd] > <span class="number">0</span> || tc[nd] > <span class="number">0</span>) {</span><br><span class="line"> <span class="type">int</span> Mid = (L + R) / <span class="number">2</span>;</span><br><span class="line"> <span class="built_in">push</span>(lc, L, Mid, ta[nd], tb[nd], tc[nd]);</span><br><span class="line"> <span class="built_in">push</span>(rc, Mid + <span class="number">1</span>, R, ta[nd], tb[nd], tc[nd]);</span><br><span class="line"> ta[nd] = tb[nd] = tc[nd] = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">build</span><span class="params">(<span class="type">int</span> nd, <span class="type">int</span> L, <span class="type">int</span> R)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (L == R)</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">void</span>( s[nd] = f[L] );</span><br><span class="line"> <span class="type">int</span> Mid = (L + R) / <span class="number">2</span>;</span><br><span class="line"> <span class="built_in">build</span>(lc, L, Mid), <span class="built_in">build</span>(rc, Mid + <span class="number">1</span>, R);</span><br><span class="line"> <span class="built_in">maintain</span>(nd);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">Mdy</span><span class="params">(<span class="type">int</span> nd, <span class="type">int</span> L, <span class="type">int</span> R, <span class="type">int</span> opL, <span class="type">int</span> opR, Z va, Z vb, Z vc)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (opL <= L && R <= opR)</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">push</span>(nd, L, R, va, vb, vc);</span><br><span class="line"> <span class="type">int</span> Mid = (L + R) / <span class="number">2</span>;</span><br><span class="line"> <span class="built_in">pushdown</span>(nd, L, R);</span><br><span class="line"> <span class="keyword">if</span> (opL <= Mid) <span class="built_in">Mdy</span>(lc, L, Mid, opL, opR, va, vb, vc);</span><br><span class="line"> <span class="keyword">if</span> (opR > Mid) <span class="built_in">Mdy</span>(rc, Mid + <span class="number">1</span>, R, opL, opR, va, vb, vc);</span><br><span class="line"> <span class="built_in">maintain</span>(nd);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function">Z <span class="title">Qry</span><span class="params">(<span class="type">int</span> nd, <span class="type">int</span> L, <span class="type">int</span> R, <span class="type">int</span> opL, <span class="type">int</span> opR)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (opL <= L && R <= opR) <span class="keyword">return</span> s[nd];</span><br><span class="line"> <span class="type">int</span> Mid = (L + R) / <span class="number">2</span>;</span><br><span class="line"> <span class="built_in">pushdown</span>(nd, L, R);</span><br><span class="line"> <span class="keyword">if</span> (opR <= Mid) <span class="keyword">return</span> <span class="built_in">Qry</span>(lc, L, Mid, opL, opR);</span><br><span class="line"> <span class="keyword">if</span> (opL > Mid) <span class="keyword">return</span> <span class="built_in">Qry</span>(rc, Mid + <span class="number">1</span>, R, opL, opR);</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Qry</span>(lc, L, Mid, opL, opR) + <span class="built_in">Qry</span>(rc, Mid + <span class="number">1</span>, R, opL, opR);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="meta">#<span class="keyword">undef</span> lc</span></span><br><span class="line"><span class="meta">#<span class="keyword">undef</span> rc</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="built_in">read</span>(n), <span class="built_in">read</span>(q);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i)</span><br><span class="line"> <span class="built_in">read</span>(A[i]), f[i] = f[i - <span class="number">1</span>] + A[i];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) f[i] += f[i - <span class="number">1</span>];</span><br><span class="line"> SGT::<span class="built_in">build</span>(<span class="number">1</span>, <span class="number">0</span>, n);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> opt, L, R, v; q; --q) {</span><br><span class="line"> <span class="type">static</span> Z d, l;</span><br><span class="line"> <span class="built_in">read</span>(opt), <span class="built_in">read</span>(L), <span class="built_in">read</span>(R);</span><br><span class="line"> <span class="keyword">if</span> (L > R) <span class="built_in">swap</span>(L, R);</span><br><span class="line"> <span class="keyword">switch</span> (opt) {</span><br><span class="line"> <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line"> <span class="built_in">read</span>(v), d = v, l = R - L + <span class="number">1</span>;</span><br><span class="line"> SGT::<span class="built_in">Mdy</span>(<span class="number">1</span>, <span class="number">0</span>, n, L, R,</span><br><span class="line"> d / <span class="number">2</span>, d * <span class="built_in">mns</span>(<span class="number">3</span>, <span class="number">2</span> * L) / <span class="number">2</span>, d * (<span class="built_in">Z</span>(L) * L - <span class="number">3</span> * L + <span class="number">2</span>) / <span class="number">2</span>);</span><br><span class="line"> <span class="keyword">if</span> (R < n)</span><br><span class="line"> SGT::<span class="built_in">Mdy</span>(<span class="number">1</span>, <span class="number">0</span>, n, R + <span class="number">1</span>, n, <span class="number">0</span>, d * l, d * l * ((l + <span class="number">1</span>) / <span class="number">2</span> - R));</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">2</span>:</span><br><span class="line"> d = SGT::<span class="built_in">Qry</span>(<span class="number">1</span>, <span class="number">0</span>, n, n, n) * (R - L + <span class="number">1</span>);</span><br><span class="line"> d -= SGT::<span class="built_in">Qry</span>(<span class="number">1</span>, <span class="number">0</span>, n, L - <span class="number">1</span>, R - <span class="number">1</span>) + SGT::<span class="built_in">Qry</span>(<span class="number">1</span>, <span class="number">0</span>, n, n - R, n - L);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, d.x);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">default</span>: <span class="built_in">fprintf</span>(stderr, <span class="string">"ERR\n"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="「BJOI2018」治疗之雨"><a href="#「BJOI2018」治疗之雨" class="headerlink" title="「BJOI2018」治疗之雨"></a>「BJOI2018」治疗之雨</h3><h4 id="题目链接-5"><a href="#题目链接-5" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://loj.ac/problem/2513">https://loj.ac/problem/2513</a></li></ul><h4 id="解题思路-5"><a href="#解题思路-5" class="headerlink" title="解题思路"></a>解题思路</h4><p>这是一道常规期望题.</p><p>设 $f_i$ 表示第一个数值为 $i$ 时, 成为最小值 $0$ 的期望步数. 记 $p_{i, j}$ 表示第一个数由 $i$ 变为 $j$ 的概率, 则有</p><script type="math/tex; mode=display">f_i = \begin{cases}\sum\limits_{j = 1} ^ {i + 1} p_{i, j} (f_j + 1) = 1 + \sum\limits_{j = 1} ^ {i + 1} p_{i, j} f_j & i < n \\\sum\limits_{j = 1} ^ n p_{i, j} (f_j + 1) = 1 + \sum\limits_{j = 1} ^ n p_{i, j} f_j & i = n\end{cases}</script><p>为计算 $p_{i, j}$, 首先设 $g_i$ 表示在一次操作中, 第一个数减少 $i$ 的概率, 则有</p><script type="math/tex; mode=display">g_i = \frac{\binom{k}{i} m ^ {k - i} }{(m + 1) ^ k}</script><p>也就是讨论 $k$ 次减小的去向. 注意此处并没有关注边界情况, 在计算 $p_{i, j}$ 的时候会考虑这一点.</p><p>$g_i$ 可以在 $O(n)$ 的时间内递推求解. 此时 $p_{i, j}$ 可表示为</p><script type="math/tex; mode=display">p_{i, j} = \begin{cases}g_{i - j} & i = n \\\frac{1}{m + 1} g_0 & j = i + 1 \\\frac{1}{m + 1} g_{i - j + 1} + \frac{m}{m + 1} g_{i - j} & j < i\end{cases}</script><p>现在就可以用高斯消元求解 $f_i$ 了. 朴素做法的时间复杂度为 $O(n ^ 3)$.</p><p>注意到本体中高斯消元的矩阵比较特殊, 在形式上类似于下三角矩阵. 那么每次将 $A_{i, i}$ 带入到其余行化简时, 有效的位置只有 $O(1)$ 个, 且完成带入后第 $n$ 行可直接确定 $f_n$. 接着利用 $f_n$ 从下向上依次回代即可解出原方程组. 此时的时间复杂度为 $O(n ^ 2)$.</p><p>同时要注意一些情况的特判, 诸如 $k = 0$, $m = 0$…</p><p>时间复杂度 $O(T n ^ 2)$.</p><h4 id="代码实现-5"><a href="#代码实现-5" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// LOJ #2513</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstring></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">1505</span>, P = <span class="number">1e9</span> + <span class="number">7</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">fpow</span><span class="params">(<span class="type">int</span> base, <span class="type">int</span> b)</span> </span>{</span><br><span class="line"> <span class="type">int</span> ret = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (b > <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">if</span> (b & <span class="number">1</span>) ret = <span class="number">1LL</span> * ret * base % P;</span><br><span class="line"> base = <span class="number">1LL</span> * base * base % P, b >>= <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">inv</span><span class="params">(<span class="type">int</span> x)</span> </span>{ <span class="keyword">return</span> <span class="built_in">fpow</span>(x, P - <span class="number">2</span>); }</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, p, m, K;</span><br><span class="line"><span class="type">int</span> ivm1;</span><br><span class="line"><span class="type">int</span> f[MAXN], g[MAXN], A[MAXN][MAXN];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">prb</span><span class="params">(<span class="type">int</span> i, <span class="type">int</span> j)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (i == n) <span class="keyword">return</span> g[i - j];</span><br><span class="line"> <span class="keyword">if</span> (j == i + <span class="number">1</span>) <span class="keyword">return</span> <span class="number">1LL</span> * ivm1 * g[<span class="number">0</span>] % P;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1LL</span> * ivm1 * (g[i - j + <span class="number">1</span>] + <span class="number">1LL</span> * m * g[i - j] % P) % P;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">solve</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (K == <span class="number">0</span>) <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line"> <span class="keyword">if</span> (m == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">if</span> (K == <span class="number">1</span>) <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line"> <span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> (p > <span class="number">0</span>) p += (p < n), p -= K, ++ret;</span><br><span class="line"> <span class="keyword">return</span> ret;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> g[<span class="number">0</span>] = <span class="built_in">fpow</span>(<span class="number">1LL</span> * m * ivm1 % P, K);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= <span class="built_in">min</span>(n + <span class="number">1</span>, K); ++i) {</span><br><span class="line"> <span class="type">int</span> s = <span class="number">1LL</span> * (K - i + <span class="number">1</span>) * <span class="built_in">inv</span>(<span class="number">1LL</span> * m * i % P) % P;</span><br><span class="line"> g[i] = <span class="number">1LL</span> * g[i - <span class="number">1</span>] * s % P;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">1</span>; j <= <span class="built_in">min</span>(i + <span class="number">1</span>, n); ++j)</span><br><span class="line"> A[i][j] = (A[i][j] - <span class="built_in">prb</span>(i, j) + P) % P;</span><br><span class="line"> A[i][n + <span class="number">1</span>] = <span class="number">1</span>, A[i][i] = (A[i][i] + <span class="number">1</span>) % P;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) {</span><br><span class="line"> <span class="type">int</span> d = <span class="built_in">inv</span>(A[i][i]);</span><br><span class="line"> A[i][i] = <span class="number">1</span>, A[i][n + <span class="number">1</span>] = <span class="number">1LL</span> * A[i][n + <span class="number">1</span>] * d % P;</span><br><span class="line"> <span class="keyword">if</span> (i < n) A[i][i + <span class="number">1</span>] = <span class="number">1LL</span> * A[i][i + <span class="number">1</span>] * d % P;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = i + <span class="number">1</span>; j <= n; ++j) { <span class="comment">// i < n</span></span><br><span class="line"> A[j][i + <span class="number">1</span>] = (A[j][i + <span class="number">1</span>] - <span class="number">1LL</span> * A[j][i] * A[i][i + <span class="number">1</span>] % P + P) % P;</span><br><span class="line"> A[j][n + <span class="number">1</span>] = (A[j][n + <span class="number">1</span>] - <span class="number">1LL</span> * A[j][i] * A[i][n + <span class="number">1</span>] % P + P) % P;</span><br><span class="line"> A[j][i] = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = n; i; --i) {</span><br><span class="line"> <span class="type">int</span> d = <span class="number">1LL</span> * A[i - <span class="number">1</span>][i] * A[i][n + <span class="number">1</span>] % P;</span><br><span class="line"> A[i - <span class="number">1</span>][n + <span class="number">1</span>] = (A[i - <span class="number">1</span>][n + <span class="number">1</span>] - d + P) % P, A[i - <span class="number">1</span>][i] = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> A[p][n + <span class="number">1</span>];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="type">int</span> Ti;</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &Ti);</span><br><span class="line"> <span class="keyword">while</span> (Ti--) {</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d%d%d"</span>, &n, &p, &m, &K);</span><br><span class="line"> ivm1 = <span class="built_in">inv</span>(m + <span class="number">1</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, <span class="built_in">solve</span>());</span><br><span class="line"></span><br><span class="line"> <span class="built_in">memset</span>(g, <span class="number">0</span>, (<span class="built_in">min</span>(n + <span class="number">1</span>, K) + <span class="number">1</span>) * <span class="built_in">sizeof</span> (<span class="type">int</span>));</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i)</span><br><span class="line"> A[i][i] = <span class="number">0</span>, A[i][n + <span class="number">1</span>] = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h3><p>要退役了, 感觉再不做点 NOI 就没有机会了 = =</p><p>去写 NOI 的题了.</p><hr>]]></content>
<summary type="html"><hr>
<p>这是 6 月份还在写省选题的悲惨故事.</p></summary>
<category term="题解" scheme="https://depletedprism.github.io/categories/%E9%A2%98%E8%A7%A3/"/>
</entry>
<entry>
<title>「UR #19」通用测评号 题解</title>
<link href="https://depletedprism.github.io/sol/oj/uoj-514/"/>
<id>https://depletedprism.github.io/sol/oj/uoj-514/</id>
<published>2020-05-27T05:05:20.000Z</published>
<updated>2024-12-16T05:34:17.306Z</updated>
<content type="html"><![CDATA[<hr><h4 id="题目链接"><a href="#题目链接" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://uoj.ac/problem/514">https://uoj.ac/problem/514</a></li></ul><p>和<a href="https://uoj.ac/problem/449">【集训队作业2018】喂鸽子</a> 几乎一样的题 (</p><span id="more"></span><p>就是算是在总结 喂鸽子 的 $O(n ^ 2 k)$ 解法了.</p><h4 id="解题思路"><a href="#解题思路" class="headerlink" title="解题思路"></a>解题思路</h4><p>如果将操作视为序列, 大力生成函数, 容易得到 50 pts 的做法, 也就是官方题解中的算法 2. <del>和<a href="https://uoj.ac/problem/390">【UNR #3】百鸽笼</a> 十分相似.</del></p><p>下文称 “放入至少 $b$ 单位的燃料” 为 “半满”, “填满 $a$ 单位的燃料” 为 “填满”.</p><p>首先对题意做一步转化, 只需计算出所有燃料舱全部半满之前, 每个燃料舱填满的概率再求和即可. 注意到燃料舱编号对答案没有影响, 不妨令填满的燃料舱编号为 $1$, 计算最终答案时乘 $n$ 就好了.</p><p>所求即满足第 $1$ 个燃料舱填满时, 不存在燃料舱仍未半满的概率. 考虑容斥, 枚举仍未半满的燃料舱个数 $m$, 同时记 $g_m$ 表示在共计 $m + 1$ 燃料舱中, 第 $1$ 个燃料舱填满时, 存在 $m$ 个燃料舱未半满的概率. (此处可直接将其余燃料舱忽略, 详见<a href="https://loj.ac/problem/2541">「PKUWC2018」猎人杀</a> 中用到的 Trick) 可得</p><script type="math/tex; mode=display">\sum_{m = 1} ^ {n - 1} (-1) ^ {m - 1} \binom{n - 1}{m}\ g_m</script><p>可以通过操作序列入手计算 $g_m$. 那么此处对操作序列的限制为 <strong>恰好</strong> 出现 $a$ 次编号 $1$, 同时有 $m$ 个编号出现次数 <strong>至多</strong> 为 $b - 1$.</p><p>但实际上, 序列中最后一次操作一定填入 $1$, 序列中未确定的位置只有 $i - 1$ 处. 因此其 EGF 为</p><script type="math/tex; mode=display">F(x) = \frac{x ^ {a - 1} }{(a - 1)!} \cdot \left( \sum_{k = 0} ^ {b - 1} \frac{x ^ k}{k!} \right) ^ m = \frac{x ^ {a - 1} }{(a - 1)!}\ G ^ m (x)</script><p>枚举序列长度为 $i$, 那么 $g_m$ 可表示为</p><script type="math/tex; mode=display">g_m = \sum_{i = 0} ^ {m (b - 1)} \frac{1}{(m + 1) ^ i} (i - 1)! \cdot [x ^ {i - 1}]\ \frac{x ^ {a - 1} }{(a - 1)!}\ G ^ m (x)</script><p>现在的问题在于如何快速计算 $G ^ m (x)$.</p><p>注意到 $G(x)$ 和 $e ^ x$ 的相似性, 并且我们知道 $(e ^ x)’ = e ^ x$. 那么可以尝试用类似的方法递推求出 $F(x)$. 具体地, 有</p><script type="math/tex; mode=display">G'(x) = \left( \sum_{k = 0} ^ {b - 1} \frac{x ^ k}{k!} \right)' = \sum_{k = 1} ^ {b - 1} \frac{k \, x ^ {k - 1} }{k!} = G(x) - \frac{x ^ {b - 1} }{(b - 1)!}</script><p>那么对于 $G ^ m (x)$, 有</p><script type="math/tex; mode=display">\big(G ^ m(x)\big)' = m \cdot G ^ {m - 1} (x) \cdot G'(x) = m \left( G ^ m(x) - \frac{x ^ {b - 1} }{(b - 1)!} G ^ {m - 1} (x) \right)</script><p>同时取项 $x ^ {i - 1}$ 系数, 可得</p><script type="math/tex; mode=display">[x ^ {i - 1}] \big(G ^ m (x)\big)' = i \cdot [x ^ i] G ^ m(x) = m \left( [x ^ {i - 1}] G ^ m (x) - [x ^ {i - 1}] \frac{x ^ {b - 1} }{(b - 1)!} G ^ {m - 1} (x) \right)</script><p>此时 $[x ^ i] G ^ m (x)$ 可通过 $[x ^ {i - 1}]G ^ m(x)$, $[x ^ {i - 1}]G ^ {m - 1} (x)$ 得出, 递推计算即可. 时间复杂度 $O(n ^ 2 b)$.</p><p>这个技巧也在<a href="https://uoj.ac/problem/449">【集训队作业2018】喂鸽子</a> 的某种 $O(n ^ 2 k)$ 做法中用到过.</p><h4 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// UOJ #514</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">255</span>, MAXM = MAXN * MAXN, P = <span class="number">998244353</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> fac[MAXM], ifac[MAXM], inv[MAXM];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">binom</span><span class="params">(<span class="type">int</span> n, <span class="type">int</span> m)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (n < m)? <span class="number">0</span>: <span class="number">1LL</span> * fac[n] * ifac[m] % P * ifac[n - m] % P;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">fpow</span><span class="params">(<span class="type">int</span> base, <span class="type">int</span> b)</span> </span>{</span><br><span class="line"> <span class="type">int</span> ret = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (b > <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">if</span> (b & <span class="number">1</span>) ret = <span class="number">1LL</span> * ret * base % P;</span><br><span class="line"> base = <span class="number">1LL</span> * base * base % P, b >>= <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">PolyPre</span><span class="params">(<span class="type">int</span> N)</span> </span>{</span><br><span class="line"> inv[<span class="number">1</span>] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">2</span>; i <= N; ++i)</span><br><span class="line"> inv[i] = <span class="number">1LL</span> * inv[P % i] * (P - P / i) % P;</span><br><span class="line"> ifac[<span class="number">0</span>] = fac[<span class="number">0</span>] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= N; ++i) {</span><br><span class="line"> fac[i] = <span class="number">1LL</span> * fac[i - <span class="number">1</span>] * i % P;</span><br><span class="line"> ifac[i] = <span class="number">1LL</span> * ifac[i - <span class="number">1</span>] * inv[i] % P;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, a, b;</span><br><span class="line"><span class="type">int</span> f[MAXN][MAXM], g[MAXN][MAXM];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d%d"</span>, &n, &a, &b);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">PolyPre</span>(n * a);</span><br><span class="line"> f[<span class="number">0</span>][<span class="number">0</span>] = <span class="number">1</span>, g[<span class="number">0</span>][b - <span class="number">1</span>] = ifac[b - <span class="number">1</span>];</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> m = <span class="number">1</span>; m <= n; ++m) {</span><br><span class="line"> f[m][<span class="number">0</span>] = <span class="number">1</span>, g[m][b - <span class="number">1</span>] = ifac[b - <span class="number">1</span>];</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= m * (b - <span class="number">1</span>); ++i) {</span><br><span class="line"> f[m][i] = <span class="number">1LL</span> * m * inv[i] % P * (f[m][i - <span class="number">1</span>] - g[m - <span class="number">1</span>][i - <span class="number">1</span>] + P) % P;</span><br><span class="line"> g[m][i + b - <span class="number">1</span>] = <span class="number">1LL</span> * f[m][i] * ifac[b - <span class="number">1</span>] % P;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> m = <span class="number">1</span>; m <= n; ++m)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i <= m * (b - <span class="number">1</span>); ++i)</span><br><span class="line"> g[m][i + a - <span class="number">1</span>] = <span class="number">1LL</span> * ifac[a - <span class="number">1</span>] * f[m][i] % P;</span><br><span class="line"> <span class="type">int</span> ans = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> m = <span class="number">1</span>; m < n; ++m) {</span><br><span class="line"> <span class="type">int</span> s = <span class="number">0</span>, pw = <span class="built_in">fpow</span>(inv[m + <span class="number">1</span>], a);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = a; i <= m * (b - <span class="number">1</span>) + a; ++i) {</span><br><span class="line"> s = (s + <span class="number">1LL</span> * fac[i - <span class="number">1</span>] * pw % P * g[m][i - <span class="number">1</span>] % P) % P;</span><br><span class="line"> pw = <span class="number">1LL</span> * pw * inv[m + <span class="number">1</span>] % P;</span><br><span class="line"> }</span><br><span class="line"> s = <span class="number">1LL</span> * s * <span class="built_in">binom</span>(n - <span class="number">1</span>, m) % P;</span><br><span class="line"> ans = (ans + ((m & <span class="number">1</span>)? s: P - s)) % P;</span><br><span class="line"> }</span><br><span class="line"> ans = <span class="number">1LL</span> * ans * n % P;</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, ans);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h4><ul><li>yhx-12243, <a href="https://yhx-12243.github.io/OI-transit/records/uoj514.html">[uoj514]通用测评号 题解</a></li><li><a href="https://peehs-moorhsum.blog.uoj.ac/blog/5486">UOJ Round #19 题解</a></li></ul><hr>]]></content>
<summary type="html"><hr>
<h4 id="题目链接"><a href="#题目链接" class="headerlink" title="题目链接"></a>题目链接</h4><ul>
<li><a href="https://uoj.ac/problem/514">https://uoj.ac/problem/514</a></li>
</ul>
<p>和<a href="https://uoj.ac/problem/449">【集训队作业2018】喂鸽子</a> 几乎一样的题 (</p></summary>
<category term="题解" scheme="https://depletedprism.github.io/categories/%E9%A2%98%E8%A7%A3/"/>
<category term="Combinatorics" scheme="https://depletedprism.github.io/tags/Combinatorics/"/>
<category term="Probability" scheme="https://depletedprism.github.io/tags/Probability/"/>
</entry>
<entry>
<title>「UNR #3」百鸽笼 题解</title>
<link href="https://depletedprism.github.io/sol/oj/uoj-390/"/>
<id>https://depletedprism.github.io/sol/oj/uoj-390/</id>
<published>2020-05-25T12:24:28.000Z</published>
<updated>2024-12-16T05:34:17.306Z</updated>
<content type="html"><![CDATA[<hr><h4 id="题目链接"><a href="#题目链接" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://uoj.ac/problem/390">https://uoj.ac/problem/390</a></li></ul><p>这是一道鸽子题.</p><span id="more"></span><h4 id="解题思路"><a href="#解题思路" class="headerlink" title="解题思路"></a>解题思路</h4><p>每次鸽子回到鸽笼时会影响概率大小, 即令 $a_i$ 减 $1$ 时会影响鸽笼总数. 但根据<a href="https://loj.ac/problem/2541">「PKUWC2018」猎人杀</a> 的结论, 认为每次选择鸽笼时, 若有 $a_i > 0$, 则直接令 $a_i$ 减 $1$; 否则再次选择.</p><p>也就是说, 可以认为已经满的鸽笼列仍可入住鸽子, 但对 $a_i$ 没有影响. 此时计算出的结果和原来限制下的结果相同.</p><p>此时将鸽子的入住顺序用一长度为 $m$ 的有标号序列描述, 序列中第 $i$ 个元素表示第 $i$ 次选择, 某只鸽子入住鸽笼的列编号. 容易发现 $m \ge N$, 因为可以重复入住, 但每只鸽子都要回到鸽笼.</p><p>不妨假设当前空出的鸽笼在第 $1$ 列, 那么序列中一定存在 <strong>恰好</strong> $a_1 - 1$ 个 $1$, 同时对于其余每个元素 $i$, <strong>至少</strong> 出现 $a_i$ 次. 类似于<a href="https://uoj.ac/problem/449">【集训队作业2018】喂鸽子</a> 的思路, 可得出该序列个数的 EGF $F(x)$ 为</p><script type="math/tex; mode=display">F(x) = \frac{x ^ {a_1 - 1}}{(a_1 - 1) !} \cdot \prod_{i \neq 1} \left(e ^ x - \sum_{k = 0} ^ {a_i - 1} \frac{x ^ k}{k!}\right)</script><p>那么计算出所有合法序列的数量, 并将最后结果除以序列个数的总数就能够得出空出鸽笼在第 $1$ 列的答案. 同时, 对每个元素做一次类似的操作即可计算最终结果.</p><p>但是 $e ^ x$ 展开后有无穷项系数, 不便于计算. 此时有一个思路 (from <a href="https://yhx-12243.github.io/OI-transit/records/uoj390.html">yhx-12243</a>), 将 $F(x)$ 视为 $x$ 和 $e ^ x$ 的二元生成函数, 那么有</p><script type="math/tex; mode=display">F(x, y) = \frac{x ^ {a_1 - 1}}{(a_1 - 1) !} \cdot \prod_{i \neq 1} \left(y - \sum_{k = 0} ^ {a_i - 1} \frac{x ^ k}{k!} \right),\; y = e ^ x</script><p>对于其中一项 $y ^ i x ^ j = e ^ {ix} x ^ j$, 其对答案的另有除其系数以外的贡献. 取 $e ^ x$ 第 $s$ 项, 则</p><script type="math/tex; mode=display">[x ^ s] e ^ {ix} \cdot x ^ j = \frac{(ix) ^ s}{s!} x ^ j = \frac{i ^ s}{s!}\ x ^ {j + s}</script><p>此时 $F(x, y)$ 各项只同 $x$ 有关. 假定 $s + j = m$, 那么 $F(x, y)$ 第 $m$ 项对答案的贡献为</p><script type="math/tex; mode=display">\frac{m!}{n ^ {m + 1} } \cdot \frac{i ^ s}{s!} = \frac{(s + j)!}{n ^ {s + j + 1} } \cdot \frac{i ^ s}{s!}</script><p>其中 $n ^ {m + 1}$ 长度为 $m$ 的序列总个数. 考虑到 $a_1$ 个鸽笼中必须剩下一个不选, 且该限制不好直接计算. 那么在计算序列总数时直接将 $a_1$ 添加到序列中, 那么每次选择都有 $n$ 种可能, 因此总数为 $n ^ {m + 1}$.</p><p>实际计算时, 我们需要求得每一项的结果的和. 即</p><script type="math/tex; mode=display">\sum_{s = 0} ^ \infty \frac{(s + j)!}{n ^ {s + j + 1} } \cdot \frac{i ^ s}{s!} = \frac{j!}{n ^ {j + 1} } \cdot \sum_{s = 0} ^ \infty \binom{s + j}{s} \left( \frac{i}{n} \right) ^ s 1 ^ {j + 1}</script><p>根据广义二项式定理, 原式可化为</p><script type="math/tex; mode=display">\frac{j!}{n ^ {j + 1} } \left( \frac{1}{1 - \frac{i}{n}} \right) ^ {j + 1} = \frac{j!}{(n - i) ^ {j + 1} }</script><p>只需枚举 $i$, $j$ 即可, 实际计算时还需乘上对应项系数, 同时要考虑 $\frac{x ^ {a_1 - 1} }{(a_1 - 1)!}$ 的影响.</p><p>对于每一种空出鸽笼的位置, 重新计算 $F(x)$ 的时间复杂度过高. 因此可直接计算</p><script type="math/tex; mode=display">\prod_{i = 1} ^ n \left(e ^ x - \sum_{k = 0} ^ {a_i - 1} \frac{x ^ k}{k!}\right)</script><p>每次在原有基础上除 $e ^ x - \sum\limits_{k = 0} ^ {a_i - 1} \dfrac{x ^ k}{k!}$ 即可. 具体实现时将乘法 “倒过来写” 就好了.</p><p>时间复杂度为 $O\big(n ^ 2 \left( \sum a_i\right) \cdot \max \{ a_i \}\big)$.</p><h4 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h4><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// UOJ #390</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstring></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> LL;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">3e1</span> + <span class="number">5</span>, MAXM = MAXN * MAXN, P = <span class="number">998244353</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> fac[MAXM], ifac[MAXM], inv[MAXM];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">fpow</span><span class="params">(<span class="type">int</span> base, <span class="type">int</span> b)</span> </span>{</span><br><span class="line"> <span class="type">int</span> ret = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (b > <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">if</span> (b & <span class="number">1</span>) ret = <span class="number">1LL</span> * ret * base % P;</span><br><span class="line"> base = <span class="number">1LL</span> * base * base % P, b >>= <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">PolyPre</span><span class="params">(<span class="type">int</span> N)</span> </span>{</span><br><span class="line"> inv[<span class="number">1</span>] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">2</span>; i <= N; ++i)</span><br><span class="line"> inv[i] = <span class="number">1LL</span> * inv[P % i] * (P - P / i) % P;</span><br><span class="line"> ifac[<span class="number">0</span>] = fac[<span class="number">0</span>] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= N; ++i) {</span><br><span class="line"> fac[i] = <span class="number">1LL</span> * fac[i - <span class="number">1</span>] * i % P;</span><br><span class="line"> ifac[i] = <span class="number">1LL</span> * ifac[i - <span class="number">1</span>] * inv[i] % P;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">pls</span><span class="params">(<span class="type">int</span>& a, <span class="type">const</span> LL& b)</span> </span>{ <span class="keyword">return</span> a = (a + b) % P; }</span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">mns</span><span class="params">(<span class="type">int</span>& a, <span class="type">const</span> LL& b)</span> </span>{ <span class="keyword">return</span> a = (a - b + P) % P; }</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n;</span><br><span class="line"><span class="type">int</span> A[MAXN], h[<span class="number">2</span>][MAXN][MAXM], g[MAXN][MAXM];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &n);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) <span class="built_in">scanf</span>(<span class="string">"%d"</span>, A + i);</span><br><span class="line"> <span class="built_in">PolyPre</span>(MAXM - <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> cur = <span class="number">1</span>, df = <span class="number">0</span>;</span><br><span class="line"> h[cur][<span class="number">0</span>][<span class="number">0</span>] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < n; ++i) {</span><br><span class="line"> <span class="built_in">memset</span>(h[cur ^ <span class="number">1</span>], <span class="number">0</span>, <span class="keyword">sizeof</span> h[cur ^ <span class="number">1</span>]);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j <= i; ++j)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">0</span>; k <= df; ++k) <span class="keyword">if</span> (h[cur][j][k] > <span class="number">0</span>) {</span><br><span class="line"> <span class="built_in">pls</span>(h[cur ^ <span class="number">1</span>][j + <span class="number">1</span>][k], h[cur][j][k]);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> l = <span class="number">0</span>; l <= A[i + <span class="number">1</span>] - <span class="number">1</span>; ++l)</span><br><span class="line"> <span class="built_in">mns</span>(h[cur ^ <span class="number">1</span>][j][k + l], <span class="number">1LL</span> * ifac[l] * h[cur][j][k] % P);</span><br><span class="line"> }</span><br><span class="line"> cur ^= <span class="number">1</span>, df += A[i + <span class="number">1</span>] - <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">int</span> (*f)[MAXM] = h[cur];</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> m = <span class="number">1</span>; m <= n; ++m) {</span><br><span class="line"> <span class="built_in">memset</span>(g, <span class="number">0</span>, <span class="keyword">sizeof</span> g);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = n - <span class="number">1</span>; j >= <span class="number">0</span>; --j)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">0</span>; k <= df - A[m] + <span class="number">1</span>; ++k) {</span><br><span class="line"> <span class="built_in">pls</span>(g[j][k], f[j + <span class="number">1</span>][k]);</span><br><span class="line"> <span class="keyword">if</span> (j == <span class="number">0</span> || g[j][k] == <span class="number">0</span>) <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> l = <span class="number">0</span>; l <= A[m] - <span class="number">1</span>; ++l)</span><br><span class="line"> <span class="built_in">pls</span>(g[j - <span class="number">1</span>][k + l], <span class="number">1LL</span> * ifac[l] * g[j][k] % P);</span><br><span class="line"> }</span><br><span class="line"> <span class="type">int</span> ans = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < n; ++i) {</span><br><span class="line"> <span class="type">int</span> j = A[m] - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">0</span>; k <= df - A[m] + <span class="number">1</span>; ++k, ++j) <span class="keyword">if</span> (g[i][k] > <span class="number">0</span>)</span><br><span class="line"> <span class="built_in">pls</span>(ans, <span class="number">1LL</span> * fac[j] * g[i][k] % P * <span class="built_in">fpow</span>(inv[n - i], j + <span class="number">1</span>) % P);</span><br><span class="line"> }</span><br><span class="line"> ans = <span class="number">1LL</span> * ans * ifac[A[m] - <span class="number">1</span>] % P;</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d%c"</span>, ans, <span class="string">" \n"</span>[m == n]);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h4><p>我承认我不可能写地比参考资料好 (</p><ul><li><a href="https://wuhongxun.blog.uoj.ac/blog/3679">UOJ NOI Round #3 Day2 题解</a></li><li>yhx-12243, <a href="https://yhx-12243.github.io/OI-transit/records/uoj390.html">UOJ #390 百鸽笼 题解</a></li><li>lyd729, <a href="https://blog.csdn.net/lyd_7_29/java/article/details/83787557">【UOJ #390】【UNR #3】百鸽笼</a></li></ul><hr>]]></content>
<summary type="html"><hr>
<h4 id="题目链接"><a href="#题目链接" class="headerlink" title="题目链接"></a>题目链接</h4><ul>
<li><a href="https://uoj.ac/problem/390">https://uoj.ac/problem/390</a></li>
</ul>
<p>这是一道鸽子题.</p></summary>
<category term="题解" scheme="https://depletedprism.github.io/categories/%E9%A2%98%E8%A7%A3/"/>
<category term="Combinatorics" scheme="https://depletedprism.github.io/tags/Combinatorics/"/>
<category term="Probability" scheme="https://depletedprism.github.io/tags/Probability/"/>
</entry>
<entry>
<title>「PKUWC2018」猎人杀 题解</title>
<link href="https://depletedprism.github.io/sol/oj/loj-2541/"/>
<id>https://depletedprism.github.io/sol/oj/loj-2541/</id>
<published>2020-05-25T05:15:02.000Z</published>
<updated>2024-12-16T05:34:17.302Z</updated>
<content type="html"><![CDATA[<hr><h4 id="题目链接"><a href="#题目链接" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://loj.ac/problem/2541">https://loj.ac/problem/2541</a></li></ul><p>这是一道经常被拿出来四处安利的题 (</p><span id="more"></span><h4 id="解题思路"><a href="#解题思路" class="headerlink" title="解题思路"></a>解题思路</h4><p>对于某一个时刻, 记 $f_i$ 为第 $i$ 个猎人当前没有死亡, 且在下一次开枪后死亡的概率. 同时, 记 $m$ 为所有猎人 $w_i$ 之和, $d$ 为已死亡猎人之和. 则有</p><script type="math/tex; mode=display">f_i = \frac{w_i}{m - d}</script><p>容易得到</p><script type="math/tex; mode=display">f_i = \frac{w_i}{m} + \frac{d}{m} f_i</script><p>考虑这个式子的实际意义. 即如果向已死亡的猎人射击, 等同于再次射击… 也就是在一猎人死亡后, 仍可认为其能被作为射击目标. 在该意义下计算并不会影响 $f_i$ 的值.</p><p>现在要解决的问题即为, 求恰好 $0$ 人在 $1$ 死亡之后死亡概率. 考虑容斥, 枚举在 $1$ 死亡后存活的猎人集合 $S$, 同时记 $s$ 为集合 $S$ 中的猎人 $w_i$ 之和. 可以得到答案为</p><script type="math/tex; mode=display">\sum_{S} (-1) ^ {|S|} \sum_{t = 0} ^ \infty (1 - \frac{s + w_1}{m}) ^ t \cdot \frac{w_1}{m} = \sum_{S} (-1) ^ {|S|} \frac{w_1}{s + w_1}</script><p>笼统解释一下, 集合 $S$ 中猎人要能在 $1$ 之后存活, 其划分界限一定为 $1$ 死亡的时刻, 并在该时刻前 $S$ 和 $1$ 都不能死亡. 后者利用广义二项式定理即可得出.</p><p>显然枚举集合是不科学的. 注意到 $\sum w_i$ 的值不大, 求出每一个 $s$ 对应的集合容斥系数之和即可. 其生成函数为</p><script type="math/tex; mode=display">F(x) = \prod_{i = 2} ^ n \left(1 - x ^ {w_i} \right)</script><p>分治 FFT 计算即可. 最终的答案为</p><script type="math/tex; mode=display">\sum_{s \ge 0} [x ^ s] F(x) \cdot \frac{w_1}{s + w_1}</script><p>记 $m = \sum\limits_{i = 1} ^ n w_i$, 则时间复杂度为 $O(m \log ^ 2 m)$.</p><h4 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h4><p>用 <code>vector</code> 代替数组写多项式果然快乐 (</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// LOJ #2541</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><vector></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> LOG = <span class="number">18</span>, MAXN = <span class="number">1</span> << LOG | <span class="number">1</span>, P = <span class="number">998244353</span>, G = <span class="number">3</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> W[LOG][MAXN];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">fpow</span><span class="params">(<span class="type">int</span> base, <span class="type">int</span> b)</span> </span>{</span><br><span class="line"> <span class="type">int</span> ret = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (b > <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">if</span> (b & <span class="number">1</span>) ret = <span class="number">1LL</span> * ret * base % P;</span><br><span class="line"> base = <span class="number">1LL</span> * base * base % P, b >>= <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> Poly {</span><br><span class="line"> <span class="type">int</span> r[MAXN];</span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">init</span><span class="params">(<span class="type">const</span> <span class="type">int</span>& Lim, <span class="type">const</span> <span class="type">int</span>& L)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i < Lim; ++i) r[i] = (r[i>><span class="number">1</span>] >> <span class="number">1</span>) | ((i & <span class="number">1</span>) << (L<span class="number">-1</span>));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">NTT</span><span class="params">(<span class="type">int</span>* f, <span class="type">const</span> <span class="type">int</span>& Lim, <span class="type">const</span> <span class="type">int</span>& type)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i < Lim; ++i) <span class="keyword">if</span> (i < r[i]) <span class="built_in">swap</span>(f[i], f[r[i]]);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">0</span>, Mid = <span class="number">1</span>; Mid < Lim; Mid <<= <span class="number">1</span>, ++k) {</span><br><span class="line"> <span class="type">const</span> <span class="type">int</span>* w = W[k];</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < Lim; i += Mid << <span class="number">1</span>)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j < Mid; ++j) {</span><br><span class="line"> <span class="type">int</span> f0 = f[i+j], f1 = <span class="number">1LL</span> * w[j] * f[i+j+Mid] % P;</span><br><span class="line"> f[i+j] = (f0 + f1) % P, f[i+j+Mid] = (f0 - f1 + P) % P;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (type < <span class="number">0</span>) {</span><br><span class="line"> <span class="type">int</span> iv = <span class="built_in">fpow</span>(Lim, P - <span class="number">2</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < Lim; ++i) f[i] = <span class="number">1LL</span> * f[i] * iv % P;</span><br><span class="line"> <span class="built_in">reverse</span>(f + <span class="number">1</span>, f + Lim);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">PolyPre</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> w, i = <span class="number">0</span>, Mid = <span class="number">1</span>; i < LOG; ++i, Mid <<= <span class="number">1</span>) {</span><br><span class="line"> W[i][<span class="number">0</span>] = <span class="number">1</span>, w = <span class="built_in">fpow</span>(G, (P - <span class="number">1</span>) / (Mid << <span class="number">1</span>));</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">1</span>; j < Mid; ++j)</span><br><span class="line"> W[i][j] = <span class="number">1LL</span> * w * W[i][j - <span class="number">1</span>] % P;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> vector<<span class="type">int</span>> poly;</span><br><span class="line"></span><br><span class="line">poly <span class="keyword">operator</span> * (<span class="type">const</span> poly& f, <span class="type">const</span> poly& g) {</span><br><span class="line"> <span class="type">static</span> <span class="type">int</span> A[MAXN], B[MAXN];</span><br><span class="line"> <span class="type">int</span> Lim = <span class="number">1</span>, L = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> (Lim < <span class="built_in">int</span>(f.<span class="built_in">size</span>() + g.<span class="built_in">size</span>())) Lim <<= <span class="number">1</span>, ++L;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < Lim; ++i) {</span><br><span class="line"> A[i] = (i < (<span class="type">int</span>) f.<span class="built_in">size</span>())? f[i]: <span class="number">0</span>;</span><br><span class="line"> B[i] = (i < (<span class="type">int</span>) g.<span class="built_in">size</span>())? g[i]: <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> Poly::<span class="built_in">init</span>(Lim, L), Poly::<span class="built_in">NTT</span>(A, Lim, <span class="number">1</span>), Poly::<span class="built_in">NTT</span>(B, Lim, <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < Lim; ++i) A[i] = <span class="number">1LL</span> * A[i] * B[i] % P;</span><br><span class="line"> Poly::<span class="built_in">NTT</span>(A, Lim, <span class="number">-1</span>);</span><br><span class="line"> <span class="function">poly <span class="title">h</span><span class="params">(f.size() + g.size() - <span class="number">1</span>)</span></span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i < h.<span class="built_in">size</span>(); ++i) h[i] = A[i];</span><br><span class="line"> <span class="keyword">return</span> h;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n;</span><br><span class="line"><span class="type">int</span> w[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="function">poly <span class="title">solve</span><span class="params">(<span class="type">int</span> L, <span class="type">int</span> R)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (L == R) {</span><br><span class="line"> <span class="function">poly <span class="title">g</span><span class="params">(w[L] + <span class="number">1</span>)</span></span>;</span><br><span class="line"> <span class="keyword">return</span> g[<span class="number">0</span>] = <span class="number">1</span>, g[w[L]] = P - <span class="number">1</span>, g;</span><br><span class="line"> }</span><br><span class="line"> <span class="type">int</span> Mid = (L + R) / <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">solve</span>(L, Mid) * <span class="built_in">solve</span>(Mid + <span class="number">1</span>, R);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &n);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) <span class="built_in">scanf</span>(<span class="string">"%d"</span>, w + i);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">PolyPre</span>();</span><br><span class="line"> poly f = <span class="built_in">solve</span>(<span class="number">2</span>, n);</span><br><span class="line"> <span class="type">int</span> ans = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < (<span class="type">int</span>) f.<span class="built_in">size</span>(); ++i) {</span><br><span class="line"> <span class="type">int</span> iv = <span class="built_in">fpow</span>((i + w[<span class="number">1</span>]) % P, P - <span class="number">2</span>);</span><br><span class="line"> ans = (ans + <span class="number">1LL</span> * w[<span class="number">1</span>] * f[i] % P * iv % P) % P;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, ans);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h4><ul><li>danihao123, <a href="https://yahyachan.github.io/2018/08/09/loj2541/">LibreOJ 2541 「PKUWC2018」猎人杀</a></li><li>zjp-shadow, <a href="https://www.cnblogs.com/zjp-shadow/p/9097283.html">LOJ #2541. 「PKUWC 2018」猎人杀(容斥, 期望dp, NTT优化)</a></li></ul><hr>]]></content>
<summary type="html"><hr>
<h4 id="题目链接"><a href="#题目链接" class="headerlink" title="题目链接"></a>题目链接</h4><ul>
<li><a href="https://loj.ac/problem/2541">https://loj.ac/problem/2541</a></li>
</ul>
<p>这是一道经常被拿出来四处安利的题 (</p></summary>
<category term="题解" scheme="https://depletedprism.github.io/categories/%E9%A2%98%E8%A7%A3/"/>
<category term="Polynomial" scheme="https://depletedprism.github.io/tags/Polynomial/"/>
<category term="Probability" scheme="https://depletedprism.github.io/tags/Probability/"/>
</entry>
<entry>
<title>容斥原理备忘录</title>
<link href="https://depletedprism.github.io/memos/inclusion-exclusion/"/>
<id>https://depletedprism.github.io/memos/inclusion-exclusion/</id>
<published>2020-05-20T01:29:31.000Z</published>
<updated>2024-12-16T05:34:17.302Z</updated>
<content type="html"><![CDATA[<hr><p>记录以备忘.</p><h2 id="综述"><a href="#综述" class="headerlink" title="综述"></a>综述</h2><p>虽然是很基础的东西, 但是不妨回头再看它一眼.</p><p>又因为本文定位于备忘, 所有不会有关于任何公式的证明, <del>其实就是公式的罗列</del>… 如果真的对证明感兴趣, 不妨去文末的参看资料看看.</p><span id="more"></span><h2 id="基础"><a href="#基础" class="headerlink" title="基础"></a>基础</h2><p>设全集 $U$ 中有 $n$ 中不同条件 $P_{i\ldots n}$, 记 $A_i$ 为满足条件 $P_i$ 元素的集合.</p><h3 id="由集合的交计算集合的并"><a href="#由集合的交计算集合的并" class="headerlink" title="由集合的交计算集合的并"></a>由集合的交计算集合的并</h3><script type="math/tex; mode=display">| \bigcup_{i = 1} ^ n A_i | = \sum_{k = 1} ^ n (-1) ^ {k - 1} \sum_{1 \le i_1,\ \cdots,\ i_k \le n} | \bigcap_{j = 1} ^ k A_{i_j} |</script><h3 id="由补集的并计算集合的交"><a href="#由补集的并计算集合的交" class="headerlink" title="由补集的并计算集合的交"></a>由补集的并计算集合的交</h3><script type="math/tex; mode=display">|\bigcap_{i = 1} ^ n A_i| = |U| - |\bigcup_{i = 1} ^ n \bar A_i|</script><p>直接将之前的式子带入, 则有</p><script type="math/tex; mode=display">|\bigcap_{i = 1} ^ n A_i| = |U| - \sum_{k = 1} ^ n (-1) ^ {k - 1} \sum_{1 \le i_1,\ \cdots,\ i_k \le n} | \bigcap_{j = 1} ^ k \bar A_{i_j} |</script><p>进一步可以得到</p><script type="math/tex; mode=display">|\bigcap_{i = 1} ^ n A_i| = \sum_{k = 0} ^ n (-1) ^ k \sum_{1 \le i_1,\ \cdots,\ i_k \le n} |\bigcap_{j = 1} ^ k \bar A_{i_j}|</script><p>至于其他情况, 可用摩根定律进行转化.</p><p>很多时候集合中元素具体是什么不会影响结果, 此时枚举集合大小同时乘一个组合数作为系数就可以得出一些式子.</p><h2 id="推广"><a href="#推广" class="headerlink" title="推广"></a>推广</h2><h3 id="二项式反演"><a href="#二项式反演" class="headerlink" title="二项式反演"></a>二项式反演</h3><script type="math/tex; mode=display">g(n) = \sum_{k = n} ^ m \binom{k}{n} f(k) \Leftrightarrow f(n) = \sum_{k = n} ^ m (-1) ^ {k - n} \binom{k}{n} g(k)</script><p>虽然本质是容斥原理, 但是在实际中可能 (?) 会更好用一点.</p><p>此时的 $f(n)$, $g(n)$ 有组合意义, 例如 $f(n)$ 表示在总共 $m$ 个物品中, 恰好选择 $n$ 个满足某个条件元素的方案数, $g(n)$ 表示钦定 $n$ 个满足某个条件元素的方案数.</p><h3 id="子集反演"><a href="#子集反演" class="headerlink" title="子集反演"></a>子集反演</h3><p>记 $f(S)$, $g(S)$ 为两个关于集合 $S$ 的函数, 那么有</p><script type="math/tex; mode=display">f(S) = \sum_{T \subseteq S} g(T) \Leftrightarrow g(S) = \sum_{T \subseteq S} (-1) ^ {|S| - |T|} f(T)</script><p>类似地, 有</p><script type="math/tex; mode=display">f(S) = \sum_{S \subseteq T} g(T) \Leftrightarrow g(S) = \sum_{S \subseteq T} (-1) ^ {|T| - |S|} f(T)</script><h3 id="Min-Max-容斥"><a href="#Min-Max-容斥" class="headerlink" title="Min-Max 容斥"></a>Min-Max 容斥</h3><p>对于一个集合 $S$, 记 $\max\{S\}$ 为集合 $S$ 中最大值, $\min\{S\}$ 为集合 $S$ 中最小值, 那么有</p><script type="math/tex; mode=display">\max\{ S \} = \sum_{T \neq \varnothing,\ T \subseteq S} (-1) ^ {|T| - 1} \min\{ T \}</script><p>同时可以推广到第 $k$ 大值. 记 $\operatorname{kmax}\{S\}$ 为集合 $S$ 中的第 $k$ 大值, 那么有</p><script type="math/tex; mode=display">\operatorname{kmax}\{ S \} = \sum_{|T| \ge k,\ T \subseteq S} (-1) ^ {|T| - k} \binom{|T| - 1}{k - 1} \min\{T\}</script><p>同时由期望的线性性可以得到</p><script type="math/tex; mode=display">E(\max\{S\}) = \sum_{T \neq \varnothing,\ T \subseteq S} (-1) ^ {|T| - 1} E(\min\{T\})</script><p>一个常见的问题为, 询问一个集合中所有元素都出现的期望时间. 此时就可以套用该公式, 从而转为计算子集中元素第一次出现的期望时间.</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li>Richard A. Brualdi. 组合数学. 机械工业出版社, 2012.4.</li><li>OI Wiki, 容斥原理, <a href="https://oi-wiki.org/math/inclusion-exclusion-principle/">https://oi-wiki.org/math/inclusion-exclusion-principle/</a></li><li>GXZlegend, 二项式反演及其应用, <a href="https://www.cnblogs.com/GXZlegend/p/11407185.html">https://www.cnblogs.com/GXZlegend/p/11407185.html</a></li><li>vfleaking, 炫酷反演魔术, <a href="http://vfleaking.blog.uoj.ac/blog/87">http://vfleaking.blog.uoj.ac/blog/87</a></li><li>GXZlegend, Min-Max容斥及其推广和应用, <a href="https://www.cnblogs.com/GXZlegend/p/11563330.html">https://www.cnblogs.com/GXZlegend/p/11563330.html</a></li></ul><hr>]]></content>
<summary type="html"><hr>
<p>记录以备忘.</p>
<h2 id="综述"><a href="#综述" class="headerlink" title="综述"></a>综述</h2><p>虽然是很基础的东西, 但是不妨回头再看它一眼.</p>
<p>又因为本文定位于备忘, 所有不会有关于任何公式的证明, <del>其实就是公式的罗列</del>… 如果真的对证明感兴趣, 不妨去文末的参看资料看看.</p></summary>
<category term="笔记" scheme="https://depletedprism.github.io/categories/%E7%AC%94%E8%AE%B0/"/>
<category term="Combinatorics" scheme="https://depletedprism.github.io/tags/Combinatorics/"/>
</entry>
<entry>
<title>TJOI 2019 简要题解</title>
<link href="https://depletedprism.github.io/sol/sx/TJOI-2019-sol/"/>
<id>https://depletedprism.github.io/sol/sx/TJOI-2019-sol/</id>
<published>2020-05-18T12:59:43.000Z</published>
<updated>2024-12-16T05:34:17.306Z</updated>
<content type="html"><![CDATA[<hr><p><del>我没有在刷水题 (确信</del></p><p>打 扰 了.</p><span id="more"></span><h3 id="「TJOI2019」甲苯先生的字符串"><a href="#「TJOI2019」甲苯先生的字符串" class="headerlink" title="「TJOI2019」甲苯先生的字符串"></a>「TJOI2019」甲苯先生的字符串</h3><h4 id="题目链接"><a href="#题目链接" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://loj.ac/problem/3104">https://loj.ac/problem/3104</a></li></ul><h4 id="解题思路"><a href="#解题思路" class="headerlink" title="解题思路"></a>解题思路</h4><p>很套路的矩阵乘法 = =</p><p>设 $f(i, c)$ 表示当前计算到 $s_2$ 中第 $i$ 位, 且第 $i$ 位字符为 $c$. 容易发现转移和 $i$ 无关, 构造矩阵加速转移即可.</p><p>时间复杂度 $O(|s_1| + \log n)$, 同时带有矩阵乘法的常数 ($26 \times 26$).</p><h4 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// LOJ #3104</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstring></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> LL;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">1e5</span> + <span class="number">5</span>, MAXM = <span class="number">26</span>, P = <span class="number">1e9</span> + <span class="number">7</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Matrix</span> {</span><br><span class="line"> <span class="type">int</span> g[MAXM][MAXM];</span><br><span class="line"> <span class="built_in">Matrix</span>() { <span class="built_in">memset</span>(g, <span class="number">0</span>, <span class="keyword">sizeof</span> g); }</span><br><span class="line"> Matrix <span class="keyword">operator</span> * (<span class="type">const</span> Matrix& rhs) <span class="type">const</span> {</span><br><span class="line"> Matrix ret;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < MAXM; ++i)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">0</span>; k < MAXM; ++k) <span class="keyword">if</span> (g[i][k] != <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j < MAXM; ++j) <span class="keyword">if</span> (rhs.g[k][j] != <span class="number">0</span>)</span><br><span class="line"> ret.g[i][j] = (ret.g[i][j] + <span class="number">1LL</span> * g[i][k] * rhs.g[k][j] % P) % P;</span><br><span class="line"> <span class="keyword">return</span> ret;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">init</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < MAXM; ++i) g[i][i] = <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="function">Matrix <span class="title">fpow</span><span class="params">(Matrix base, LL b)</span> </span>{</span><br><span class="line"> Matrix ret; ret.<span class="built_in">init</span>();</span><br><span class="line"> <span class="keyword">while</span> (b > <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">if</span> (b & <span class="number">1</span>) ret = ret * base;</span><br><span class="line"> base = base * base, b >>= <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> m; LL n;</span><br><span class="line"><span class="type">char</span> S[MAXN];</span><br><span class="line"></span><br><span class="line">Matrix f, g;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%lld%s"</span>, &n, S + <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"> m = (<span class="type">int</span>) <span class="built_in">strlen</span>(S + <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < MAXM; ++i)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j < MAXM; ++j) f.g[i][j] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i < m; ++i) {</span><br><span class="line"> <span class="type">int</span> c1 = S[i] - <span class="string">'a'</span>, c2 = S[i + <span class="number">1</span>] - <span class="string">'a'</span>;</span><br><span class="line"> f.g[c1][c2] = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> g = <span class="built_in">fpow</span>(f, n - <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> ans = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < MAXM; ++i)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j < MAXM; ++j) ans = (ans + g.g[i][j]) % P;</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, ans);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="「TJOI2019」甲苯先生的滚榜"><a href="#「TJOI2019」甲苯先生的滚榜" class="headerlink" title="「TJOI2019」甲苯先生的滚榜"></a>「TJOI2019」甲苯先生的滚榜</h3><h4 id="题目链接-1"><a href="#题目链接-1" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://loj.ac/problem/3105">https://loj.ac/problem/3105</a></li></ul><h4 id="解题思路-1"><a href="#解题思路-1" class="headerlink" title="解题思路"></a>解题思路</h4><p>这是一道平衡树模板题.</p><p>唯一需要注意的地方是, 该题中排名指所有元素中, 严格大于某元素的个数. 同常见的 “求 <code>rank</code>“ 有些许不同.</p><p>时间复杂度 $O\big(T (n + m) \log m\big)$.</p><h4 id="代码实现-1"><a href="#代码实现-1" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// LOJ #3105</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdlib></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">1.5e6</span> + <span class="number">5</span>, MAXM = <span class="number">1e5</span> + <span class="number">5</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">unsigned</span> <span class="title">randNum</span><span class="params">(<span class="type">unsigned</span>& seed, <span class="type">unsigned</span> lst, <span class="type">const</span> <span class="type">int</span>& m)</span></span>{ </span><br><span class="line"> <span class="keyword">return</span> seed = seed * <span class="number">17</span> + lst, seed % m + <span class="number">1</span>; </span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Item</span> {</span><br><span class="line"> <span class="type">int</span> c, p;</span><br><span class="line"> <span class="built_in">Item</span>() { c = p = <span class="number">0</span>; }</span><br><span class="line"> <span class="built_in">Item</span>(<span class="type">int</span> _c, <span class="type">int</span> _p): <span class="built_in">c</span>(_c), <span class="built_in">p</span>(_p) { }</span><br><span class="line"> <span class="type">bool</span> <span class="keyword">operator</span> < (<span class="type">const</span> Item& rhs) <span class="type">const</span> {</span><br><span class="line"> <span class="keyword">return</span> c < rhs.c || (c == rhs.c && p > rhs.p);</span><br><span class="line"> }</span><br><span class="line"> <span class="type">bool</span> <span class="keyword">operator</span> == (<span class="type">const</span> Item& rhs) <span class="type">const</span> {</span><br><span class="line"> <span class="keyword">return</span> !(*<span class="keyword">this</span> < rhs) && !(rhs < *<span class="keyword">this</span>);</span><br><span class="line"> }</span><br><span class="line">} A[MAXM];</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, m, root; <span class="type">unsigned</span> seed;</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> Splay {</span><br><span class="line"> Item val[MAXN];</span><br><span class="line"> <span class="type">int</span> ch[<span class="number">2</span>][MAXN], pre[MAXN], size[MAXN], cnt[MAXN], nidx;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">newnode</span><span class="params">(<span class="type">const</span> Item& v)</span> </span>{</span><br><span class="line"> <span class="type">int</span> nd = ++nidx;</span><br><span class="line"> ch[<span class="number">0</span>][nd] = ch[<span class="number">1</span>][nd] = pre[nd] = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">return</span> val[nd] = v, size[nd] = cnt[nd] = <span class="number">1</span>, nd;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">maintain</span><span class="params">(<span class="type">const</span> <span class="type">int</span>& nd)</span> </span>{</span><br><span class="line"> size[nd] = cnt[nd];</span><br><span class="line"> <span class="keyword">if</span> (ch[<span class="number">0</span>][nd]) size[nd] += size[ch[<span class="number">0</span>][nd]];</span><br><span class="line"> <span class="keyword">if</span> (ch[<span class="number">1</span>][nd]) size[nd] += size[ch[<span class="number">1</span>][nd]];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">which</span><span class="params">(<span class="type">const</span> <span class="type">int</span>& u)</span> </span>{ <span class="keyword">return</span> pre[u]? ch[<span class="number">1</span>][pre[u]] == u: <span class="number">0</span>; }</span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">connect</span><span class="params">(<span class="type">int</span> u, <span class="type">int</span> fa, <span class="type">const</span> <span class="type">int</span>& w)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (u) pre[u] = fa;</span><br><span class="line"> <span class="keyword">if</span> (fa) ch[w][fa] = u; <span class="keyword">else</span> root = u;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">rotate</span><span class="params">(<span class="type">const</span> <span class="type">int</span>& u)</span> </span>{</span><br><span class="line"> <span class="type">int</span> fa = pre[u], w = <span class="built_in">which</span>(u);</span><br><span class="line"> <span class="built_in">connect</span>(u, pre[fa], <span class="built_in">which</span>(fa));</span><br><span class="line"> <span class="built_in">connect</span>(ch[w ^ <span class="number">1</span>][u], fa, w), <span class="built_in">connect</span>(fa, u, w ^ <span class="number">1</span>);</span><br><span class="line"> <span class="built_in">maintain</span>(fa);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">splay</span><span class="params">(<span class="type">const</span> <span class="type">int</span>& u, <span class="type">int</span> v)</span> </span>{</span><br><span class="line"> v = pre[v];</span><br><span class="line"> <span class="keyword">while</span> (pre[u] != v) {</span><br><span class="line"> <span class="type">int</span> fa = pre[u];</span><br><span class="line"> <span class="keyword">if</span> (pre[fa] != v) <span class="built_in">which</span>(u) == <span class="built_in">which</span>(fa)? <span class="built_in">rotate</span>(fa): <span class="built_in">rotate</span>(u);</span><br><span class="line"> <span class="built_in">rotate</span>(u);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">maintain</span>(u);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">Ins</span><span class="params">(<span class="type">const</span> Item& v)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (!root) <span class="keyword">return</span> <span class="built_in">void</span>( root = <span class="built_in">newnode</span>(v) );</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> nd = root; nd; nd = ch[val[nd] < v][nd]) {</span><br><span class="line"> <span class="keyword">if</span> (val[nd] == v) <span class="keyword">return</span> ++cnt[nd], <span class="built_in">splay</span>(nd, root);</span><br><span class="line"> <span class="keyword">if</span> (!ch[val[nd] < v][nd]) {</span><br><span class="line"> ch[val[nd] < v][nd] = <span class="built_in">newnode</span>(v);</span><br><span class="line"> <span class="keyword">return</span> pre[nidx] = nd, <span class="built_in">splay</span>(nidx, root);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">Fnd</span><span class="params">(<span class="type">const</span> Item& v)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> nd = root; nd; nd = ch[val[nd] < v][nd])</span><br><span class="line"> <span class="keyword">if</span> (val[nd] == v) <span class="keyword">return</span> <span class="built_in">splay</span>(nd, root);</span><br><span class="line"> <span class="built_in">abort</span>();</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">Rmv</span><span class="params">(<span class="type">const</span> Item& v)</span> </span>{</span><br><span class="line"> <span class="built_in">Fnd</span>(v);</span><br><span class="line"> <span class="keyword">if</span> (cnt[root] > <span class="number">1</span>) <span class="keyword">return</span> <span class="built_in">void</span>( --cnt[root] );</span><br><span class="line"> <span class="keyword">if</span> (!ch[<span class="number">0</span>][root] && !ch[<span class="number">1</span>][root])</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">void</span>( root = <span class="number">0</span> );</span><br><span class="line"> <span class="keyword">if</span> (!ch[<span class="number">0</span>][root] || !ch[<span class="number">1</span>][root]) {</span><br><span class="line"> <span class="type">int</span> w = !ch[<span class="number">0</span>][root];</span><br><span class="line"> <span class="keyword">return</span> root = ch[w][root], <span class="built_in">void</span>( pre[root] = <span class="number">0</span> );</span><br><span class="line"> }</span><br><span class="line"> <span class="type">int</span> nd = ch[<span class="number">0</span>][root];</span><br><span class="line"> <span class="keyword">while</span> (ch[<span class="number">1</span>][nd] > <span class="number">0</span>) nd = ch[<span class="number">1</span>][nd];</span><br><span class="line"> <span class="built_in">splay</span>(nd, ch[<span class="number">0</span>][root]);</span><br><span class="line"> ch[<span class="number">1</span>][nd] = ch[<span class="number">1</span>][root], pre[nd] = <span class="number">0</span>, root = pre[ch[<span class="number">1</span>][nd]] = nd;</span><br><span class="line"> <span class="built_in">maintain</span>(nd);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">Rnk</span><span class="params">(<span class="type">const</span> Item& v)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Ins</span>(v), size[ch[<span class="number">1</span>][root]];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="type">int</span> Ti, lstans = <span class="number">7</span>;</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &Ti);</span><br><span class="line"> <span class="keyword">while</span> (Ti--) {</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d%u"</span>, &m, &n, &seed);</span><br><span class="line"></span><br><span class="line"> Splay::nidx = root = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= m; ++i)</span><br><span class="line"> A[i] = <span class="built_in">Item</span>(<span class="number">0</span>, <span class="number">0</span>), Splay::<span class="built_in">Ins</span>(A[i]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> x, y; n; --n) {</span><br><span class="line"> x = <span class="built_in">randNum</span>(seed, lstans, m), y = <span class="built_in">randNum</span>(seed, lstans, m);</span><br><span class="line"> Splay::<span class="built_in">Rmv</span>(A[x]), ++A[x].c, A[x].p += y;</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, lstans = Splay::<span class="built_in">Rnk</span>(A[x]));</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="「TJOI2019」唱、跳、rap-和篮球"><a href="#「TJOI2019」唱、跳、rap-和篮球" class="headerlink" title="「TJOI2019」唱、跳、rap 和篮球"></a>「TJOI2019」唱、跳、rap 和篮球</h3><h4 id="题目链接-2"><a href="#题目链接-2" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://loj.ac/problem/3106">https://loj.ac/problem/3106</a></li></ul><h4 id="解题思路-2"><a href="#解题思路-2" class="headerlink" title="解题思路"></a>解题思路</h4><p>我们可用容斥原理计算讨论 [数据删除] 的队伍数.</p><p>记 $A_i$ 表示满足队伍中存在 $i$ 组讨论 [数据删除] 的集合, 最多情况下讨论 [数据删除] 的组数为 $m = \min \{ a, b, c, d, \lfloor \frac{n}{4} \rfloor \}$. 那么所有 $A_i$ 的补集交即为所求. 根据容斥原理可得</p><script type="math/tex; mode=display">|\bigcap_{i = 1} ^ m \bar A_i| = \sum_{k = 0} ^ m (-1) ^ k \sum_{1 \le i_1,\ \cdots,\ i_k \le n} |\bigcap_{j = 1} ^ k A_{i_j}|</script><p>队伍中每组讨论各在那个位置并不重要, 因此可枚举讨论组数 $k$, 得</p><script type="math/tex; mode=display">\sum_{k = 0} ^ m (-1) ^ k \binom{n - 3k}{k}\ g(n - 4k, a - k, b - k, c - k, d - k)</script><p>系数 $\binom{n - 3k}{k}$ 表示在队伍中选出 $k$ 组讨论的方案数. 可将每组讨论看作一个人, 那么队伍中人数为 $n - 3k$, 从中选择 $k$ 人作为讨论, 从而得到. </p><p>同时, $g(n, a, b, c, d)$ 表示剩余学生的排列数, 也就是可重集合的排列数. 即</p><script type="math/tex; mode=display">g(n, a, b, c, d) = \sum_{x_1 + x_2 + x_3 + x_4 = n} \binom{n}{x_1\; x_2\; x_3\; x_4} = n! \cdot \sum_{x_1 + x_2 + x_3 + x_4 = n} \frac{1}{x_1!\ x_2!\ x_3!\ x_4!}</script><p>其中 $x_1, x_2, x_3, x_4$ 满足 $x_1 \le a, x_2 \le b, x_3 \le c, x_4 \le d$.</p><p>显然是卷积的形式, 利用 NTT 计算 $g$ 即可.</p><p>时间复杂度 $O(n ^ 2 \log n)$. 似乎存在更加优秀的做法?</p><h4 id="代码实现-2"><a href="#代码实现-2" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// LOJ #3106</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> LOG = <span class="number">13</span>, MAXN = <span class="number">1</span> << LOG | <span class="number">1</span>, P = <span class="number">998244353</span>, G = <span class="number">3</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> W[LOG][MAXN];</span><br><span class="line"><span class="type">int</span> fac[MAXN], ifac[MAXN], inv[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">binom</span><span class="params">(<span class="type">int</span> n, <span class="type">int</span> m)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (n < m)? <span class="number">0</span>: <span class="number">1LL</span> * fac[n] * ifac[m] % P * ifac[n - m] % P;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">fpow</span><span class="params">(<span class="type">int</span> base, <span class="type">int</span> b)</span> </span>{</span><br><span class="line"> <span class="type">int</span> ret = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (b > <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">if</span> (b & <span class="number">1</span>) ret = <span class="number">1LL</span> * ret * base % P;</span><br><span class="line"> base = <span class="number">1LL</span> * base * base % P, b >>= <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> Poly {</span><br><span class="line"> <span class="type">int</span> r[MAXN];</span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">init</span><span class="params">(<span class="type">const</span> <span class="type">int</span>& Lim, <span class="type">const</span> <span class="type">int</span>& L)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i < Lim; ++i) r[i] = (r[i>><span class="number">1</span>] >> <span class="number">1</span>) | ((i & <span class="number">1</span>) << (L<span class="number">-1</span>));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">NTT</span><span class="params">(<span class="type">int</span>* f, <span class="type">const</span> <span class="type">int</span>& Lim, <span class="type">const</span> <span class="type">int</span>& type)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i < Lim; ++i) <span class="keyword">if</span> (i < r[i]) <span class="built_in">swap</span>(f[i], f[r[i]]);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">0</span>, Mid = <span class="number">1</span>; Mid < Lim; Mid <<= <span class="number">1</span>, ++k) {</span><br><span class="line"> <span class="type">const</span> <span class="type">int</span>* w = W[k];</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < Lim; i += Mid << <span class="number">1</span>)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j < Mid; ++j) {</span><br><span class="line"> <span class="type">int</span> f0 = f[i+j], f1 = <span class="number">1LL</span> * w[j] * f[i+j+Mid] % P;</span><br><span class="line"> f[i+j] = (f0 + f1) % P, f[i+j+Mid] = (f0 - f1 + P) % P;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (type < <span class="number">0</span>) {</span><br><span class="line"> <span class="type">int</span> inv = <span class="built_in">fpow</span>(Lim, P - <span class="number">2</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < Lim; ++i) f[i] = <span class="number">1LL</span> * f[i] * inv % P;</span><br><span class="line"> <span class="built_in">reverse</span>(f + <span class="number">1</span>, f + Lim);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">PolyPre</span><span class="params">(<span class="type">int</span> N)</span> </span>{</span><br><span class="line"> inv[<span class="number">1</span>] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">2</span>; i <= N; ++i)</span><br><span class="line"> inv[i] = <span class="number">1LL</span> * inv[P % i] * (P - P / i) % P;</span><br><span class="line"> fac[<span class="number">0</span>] = ifac[<span class="number">0</span>] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= N; ++i) {</span><br><span class="line"> fac[i] = <span class="number">1LL</span> * i * fac[i - <span class="number">1</span>] % P;</span><br><span class="line"> ifac[i] = <span class="number">1LL</span> * inv[i] * ifac[i - <span class="number">1</span>] % P;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> w, i = <span class="number">0</span>, Mid = <span class="number">1</span>; i < LOG; ++i, Mid <<= <span class="number">1</span>) {</span><br><span class="line"> W[i][<span class="number">0</span>] = <span class="number">1</span>, w = <span class="built_in">fpow</span>(G, (P - <span class="number">1</span>) / (Mid << <span class="number">1</span>));</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">1</span>; j < Mid; ++j)</span><br><span class="line"> W[i][j] = <span class="number">1LL</span> * w * W[i][j - <span class="number">1</span>] % P;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">g</span><span class="params">(<span class="type">int</span> n, <span class="type">int</span> a, <span class="type">int</span> b, <span class="type">int</span> c, <span class="type">int</span> d)</span> </span>{</span><br><span class="line"> <span class="type">static</span> <span class="type">int</span> A[MAXN], B[MAXN], C[MAXN], D[MAXN], f[MAXN];</span><br><span class="line"> <span class="type">int</span> Lim = <span class="number">1</span>, L = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> (Lim <= <span class="number">2</span> * (a + b + c + d)) Lim <<= <span class="number">1</span>, ++L;</span><br><span class="line"> Poly::<span class="built_in">init</span>(Lim, L);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < Lim; ++i) {</span><br><span class="line"> A[i] = (i <= a)? ifac[i]: <span class="number">0</span>, B[i] = (i <= b)? ifac[i]: <span class="number">0</span>;</span><br><span class="line"> C[i] = (i <= c)? ifac[i]: <span class="number">0</span>, D[i] = (i <= d)? ifac[i]: <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> Poly::<span class="built_in">NTT</span>(A, Lim, <span class="number">1</span>), Poly::<span class="built_in">NTT</span>(B, Lim, <span class="number">1</span>);</span><br><span class="line"> Poly::<span class="built_in">NTT</span>(C, Lim, <span class="number">1</span>), Poly::<span class="built_in">NTT</span>(D, Lim, <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i < Lim; ++i)</span><br><span class="line"> f[i] = <span class="number">1LL</span> * A[i] * B[i] % P * C[i] % P * D[i] % P;</span><br><span class="line"> Poly::<span class="built_in">NTT</span>(f, Lim, <span class="number">-1</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1LL</span> * f[n] * fac[n] % P;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, a, b, c, d;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d%d%d%d"</span>, &n, &a, &b, &c, &d);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (a + b + c + d < n)</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">puts</span>(<span class="string">"0"</span>), <span class="number">0</span>;</span><br><span class="line"> <span class="built_in">PolyPre</span>(<span class="number">2</span> * n);</span><br><span class="line"> <span class="type">int</span> N = <span class="built_in">min</span>(<span class="built_in">min</span>(a, <span class="built_in">min</span>(b, <span class="built_in">min</span>(c, d))), n / <span class="number">4</span>), ans = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i <= N; ++i) {</span><br><span class="line"> <span class="type">int</span> s = <span class="built_in">g</span>(n - <span class="number">4</span> * i, a - i, b - i, c - i, d - i) % P;</span><br><span class="line"> ans = (ans + <span class="number">1LL</span> * <span class="built_in">binom</span>(n - <span class="number">3</span> * i, i) * ((i & <span class="number">1</span>)? P - s: s) % P) % P;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, ans);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="「TJOI2019」大中锋的游乐场"><a href="#「TJOI2019」大中锋的游乐场" class="headerlink" title="「TJOI2019」大中锋的游乐场"></a>「TJOI2019」大中锋的游乐场</h3><h4 id="题目链接-3"><a href="#题目链接-3" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://loj.ac/problem/3107">https://loj.ac/problem/3107</a></li></ul><h4 id="解题思路-3"><a href="#解题思路-3" class="headerlink" title="解题思路"></a>解题思路</h4><p>注意到 $k \le 10$, 那么设 $f(i, j)$ 表示从起点 $s$ 出发到第 $i$ 个位置, 汉堡和可乐个数差值为 $j$ 时的最短路, 其中 $-k \le j \le k$.</p><p>直接在 Dijkstra 的过程中计算即可, 注意 $j$ 的范围, 以及不要忘了在起点处更新 $j$. 本质上为分层图最短路.</p><p>时间复杂度 $O(T n k \log m)$.</p><h4 id="代码实现-3"><a href="#代码实现-3" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// LOJ #3107</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><queue></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cctype></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstring></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> IO {</span><br><span class="line"> <span class="type">const</span> <span class="type">int</span> MAXSIZE = <span class="number">1</span> << <span class="number">18</span> | <span class="number">1</span>;</span><br><span class="line"> <span class="type">char</span> buf[MAXSIZE], *p1, *p2;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">Gc</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> p1 == p2 &&</span><br><span class="line"> (p2 = (p1 = buf) + <span class="built_in">fread</span>(buf, <span class="number">1</span>, MAXSIZE, stdin), p1 == p2)? EOF: *p1++;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">template</span><<span class="keyword">typename</span> T> <span class="keyword">inline</span> <span class="type">void</span> <span class="title">read</span><span class="params">(T& x)</span> </span>{</span><br><span class="line"> x = <span class="number">0</span>; <span class="type">int</span> f = <span class="number">0</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (!<span class="built_in">isdigit</span>(ch)) f |= ch == <span class="string">'-'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">isdigit</span>(ch)) x = x * <span class="number">10</span> + ch - <span class="string">'0'</span>, ch = <span class="built_in">Gc</span>();</span><br><span class="line"> <span class="keyword">if</span> (f) x = -x;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">using</span> IO::read;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">1e4</span> + <span class="number">5</span>, MAXM = <span class="number">1e5</span> + <span class="number">5</span>, MAXK = <span class="number">1e1</span> + <span class="number">5</span>, INF = <span class="number">0x3f3f3f3f</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, m, K, s, t;</span><br><span class="line"><span class="type">int</span> A[MAXN], d[MAXN][MAXK];</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> Graph {</span><br><span class="line"> <span class="keyword">struct</span> <span class="title class_">Edge</span> { <span class="type">int</span> nxt, to, w; } edges[MAXM << <span class="number">1</span>];</span><br><span class="line"> <span class="type">int</span> head[MAXN], eidx;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">init</span><span class="params">()</span> </span>{ <span class="built_in">memset</span>(head, <span class="number">-1</span>, <span class="keyword">sizeof</span> head), eidx = <span class="number">1</span>; }</span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">AddEdge</span><span class="params">(<span class="type">int</span> from, <span class="type">int</span> to, <span class="type">int</span> w)</span> </span>{</span><br><span class="line"> edges[++eidx] = (Edge){ head[from], to, w }, head[from] = eidx;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">struct</span> <span class="title class_">Node</span> {</span><br><span class="line"> <span class="type">int</span> u, k, d;</span><br><span class="line"> <span class="built_in">Node</span>(<span class="type">int</span> _u, <span class="type">int</span> _k, <span class="type">int</span> _d): <span class="built_in">u</span>(_u), <span class="built_in">k</span>(_k), <span class="built_in">d</span>(_d) { }</span><br><span class="line"> <span class="type">bool</span> <span class="keyword">operator</span> < (<span class="type">const</span> Node& rhs) <span class="type">const</span> { <span class="keyword">return</span> d > rhs.d; }</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">int</span> <span class="title">Dijkstra</span><span class="params">()</span> </span>{</span><br><span class="line"> priority_queue<Node> PQ;</span><br><span class="line"> <span class="built_in">memset</span>(d, <span class="number">0x3f</span>, <span class="keyword">sizeof</span> d);</span><br><span class="line"> PQ.<span class="built_in">push</span>(<span class="built_in">Node</span>(s, K + A[s], d[s][K + A[s]] = <span class="number">0</span>));</span><br><span class="line"> <span class="keyword">while</span> (!PQ.<span class="built_in">empty</span>()) {</span><br><span class="line"> <span class="type">int</span> u = PQ.<span class="built_in">top</span>().u, k = PQ.<span class="built_in">top</span>().k, w = PQ.<span class="built_in">top</span>().d; PQ.<span class="built_in">pop</span>();</span><br><span class="line"> <span class="keyword">if</span> (d[u][k] != w) <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = head[u]; ~i; i = edges[i].nxt) {</span><br><span class="line"> <span class="type">int</span> v = edges[i].to, vk = k + A[v];</span><br><span class="line"> <span class="keyword">if</span> (<span class="number">0</span> <= vk && vk <= <span class="number">2</span> * K && d[v][vk] > d[u][k] + edges[i].w)</span><br><span class="line"> PQ.<span class="built_in">push</span>(<span class="built_in">Node</span>(v, vk, d[v][vk] = d[u][k] + edges[i].w));</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="type">int</span> ret = INF;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">0</span>; k <= <span class="number">2</span> * K; ++k) ret = <span class="built_in">min</span>(ret, d[t][k]);</span><br><span class="line"> <span class="keyword">return</span> ret < INF? ret: <span class="number">-1</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="type">int</span> Ti; <span class="built_in">read</span>(Ti);</span><br><span class="line"> <span class="keyword">while</span> (Ti--) {</span><br><span class="line"> Graph::<span class="built_in">init</span>();</span><br><span class="line"></span><br><span class="line"> <span class="built_in">read</span>(n), <span class="built_in">read</span>(m), <span class="built_in">read</span>(K);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i)</span><br><span class="line"> <span class="built_in">read</span>(A[i]), A[i] = (A[i] == <span class="number">1</span>)? <span class="number">1</span>: <span class="number">-1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> u, v, w, i = <span class="number">1</span>; i <= m; ++i) {</span><br><span class="line"> <span class="built_in">read</span>(u), <span class="built_in">read</span>(v), <span class="built_in">read</span>(w);</span><br><span class="line"> Graph::<span class="built_in">AddEdge</span>(u, v, w), Graph::<span class="built_in">AddEdge</span>(v, u, w);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">read</span>(s), <span class="built_in">read</span>(t);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, Graph::<span class="built_in">Dijkstra</span>());</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="「TJOI2019」甲苯先生和大中锋的字符串"><a href="#「TJOI2019」甲苯先生和大中锋的字符串" class="headerlink" title="「TJOI2019」甲苯先生和大中锋的字符串"></a>「TJOI2019」甲苯先生和大中锋的字符串</h3><h4 id="题目链接-4"><a href="#题目链接-4" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><a href="https://loj.ac/problem/3108">https://loj.ac/problem/3108</a></li></ul><h4 id="解题思路-4"><a href="#解题思路-4" class="headerlink" title="解题思路"></a>解题思路</h4><p>首先有一个 (可能)? 不太常用的 SAM 性质:</p><blockquote><p>对于每一个状态 $v$ ,一个或多个子串与之匹配。我们记 $longest(v)$ 为其中最长的一个字符串,记 $len(v)$ 为它的长度。类似地,记 $shortest(v)$ 为最短的子串,它的长度为 $minlen(v)$ 。那么对应这个状态的所有字符串都是字符串 $longest(v)$ 的不同的后缀,且所有字符串的长度恰好覆盖区间 $[minlen(v),len(v)]$ 中的每一个整数。</p><p>对于初始状态 $t_0$ 以外的状态 $v$ ,可用后缀链接 $link(v)$ 表达 $minlen(v)$ :</p><script type="math/tex; mode=display">minlen(v)=len(link(v))+1.</script><p>from <a href="https://oi-wiki.org/string/sam/#_4">OI Wiki</a></p></blockquote><p>那么在建出 SAM 后, 对于一个每个包含出现 $k$ 次子串的状态 $v$, 在长度区间 $\Big(len\big(link(v)\big), len(v)\Big]$ 上 $+1$, 最后统计答案即可. 可利用差分实现.</p><p>时间复杂度 $O(Tn)$.</p><h4 id="代码实现-4"><a href="#代码实现-4" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// LOJ #3108</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstring></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">2e5</span> + <span class="number">5</span>, SIGMA = <span class="number">26</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, K;</span><br><span class="line"><span class="type">char</span> S[MAXN];</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> SAM {</span><br><span class="line"> <span class="type">int</span> ch[MAXN][SIGMA], lnk[MAXN], len[MAXN], size[MAXN], lst, nidx;</span><br><span class="line"> <span class="type">int</span> f[MAXN], cnt[MAXN], idx[MAXN];</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">newnode</span><span class="params">(<span class="type">const</span> <span class="type">int</span>& l)</span> </span>{</span><br><span class="line"> len[++nidx] = l, lnk[nidx] = <span class="number">0</span>, size[nidx] = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">memset</span>(ch[nidx], <span class="number">0</span>, <span class="keyword">sizeof</span> ch[nidx]), nidx;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">init</span><span class="params">()</span> </span>{ nidx = <span class="number">0</span>, lst = <span class="built_in">newnode</span>(<span class="number">0</span>); }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">void</span> <span class="title">Ins</span><span class="params">(<span class="type">const</span> <span class="type">int</span>& v)</span> </span>{</span><br><span class="line"> <span class="type">int</span> nd = <span class="built_in">newnode</span>(len[lst] + <span class="number">1</span>), p = lst;</span><br><span class="line"> size[nd] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (p && !ch[p][v]) ch[p][v] = nd, p = lnk[p];</span><br><span class="line"> <span class="keyword">if</span> (!p) lnk[nd] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> <span class="type">int</span> q = ch[p][v];</span><br><span class="line"> <span class="keyword">if</span> (len[q] == len[p] + <span class="number">1</span>) lnk[nd] = q;</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> <span class="type">int</span> nxt = <span class="built_in">newnode</span>(len[p] + <span class="number">1</span>);</span><br><span class="line"> lnk[nxt] = lnk[q], <span class="built_in">memcpy</span>(ch[nxt], ch[q], <span class="keyword">sizeof</span> ch[nxt]);</span><br><span class="line"> <span class="keyword">while</span> (p && ch[p][v] == q) ch[p][v] = nxt, p = lnk[p];</span><br><span class="line"> lnk[nd] = lnk[q] = nxt;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> lst = nd;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">Mdy</span><span class="params">(<span class="type">const</span> <span class="type">int</span>& L, <span class="type">const</span> <span class="type">int</span>& R)</span> </span>{ ++f[L], --f[R + <span class="number">1</span>]; }</span><br><span class="line"> <span class="function"><span class="type">int</span> <span class="title">solve</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="built_in">memset</span>(f, <span class="number">0</span>, (n + <span class="number">1</span>) * <span class="built_in">sizeof</span> (<span class="type">int</span>));</span><br><span class="line"> <span class="built_in">memset</span>(cnt, <span class="number">0</span>, (n + <span class="number">1</span>) * <span class="built_in">sizeof</span> (<span class="type">int</span>));</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= nidx; ++i) ++cnt[len[i]];</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) cnt[i] += cnt[i - <span class="number">1</span>];</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = nidx; i; --i) idx[cnt[len[i]]--] = i;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> u, i = nidx; i; --i) {</span><br><span class="line"> u = idx[i], size[lnk[u]] += size[u];</span><br><span class="line"> <span class="keyword">if</span> (size[u] == K) <span class="built_in">Mdy</span>(len[lnk[u]] + <span class="number">1</span>, len[u]);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) f[i] += f[i - <span class="number">1</span>];</span><br><span class="line"> <span class="type">int</span> ret = <span class="number">-1</span>, Mx = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = n; i; --i)</span><br><span class="line"> <span class="keyword">if</span> (f[i] > Mx) Mx = f[i], ret = i;</span><br><span class="line"> <span class="keyword">return</span> ret;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="type">int</span> Ti;</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &Ti);</span><br><span class="line"> <span class="keyword">while</span> (Ti--) {</span><br><span class="line"> SAM::<span class="built_in">init</span>(), <span class="built_in">scanf</span>(<span class="string">"%s%d"</span>, S + <span class="number">1</span>, &K);</span><br><span class="line"> n = (<span class="type">int</span>) <span class="built_in">strlen</span>(S + <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= n; ++i) SAM::<span class="built_in">Ins</span>(S[i] - <span class="string">'a'</span>);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, SAM::<span class="built_in">solve</span>());</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><h3 id="「TJOI2019」甲苯先生的线段树"><a href="#「TJOI2019」甲苯先生的线段树" class="headerlink" title="「TJOI2019」甲苯先生的线段树"></a>「TJOI2019」甲苯先生的线段树</h3><h4 id="题目链接-5"><a href="#题目链接-5" class="headerlink" title="题目链接"></a>题目链接</h4><ul><li><del><a href="https://loj.ac/problem/3109">https://loj.ac/problem/3109</a></del></li><li><a href="https://codeforces.com/problemset/problem/750/G">https://codeforces.com/problemset/problem/750/G</a></li></ul><h4 id="解题思路-5"><a href="#解题思路-5" class="headerlink" title="解题思路"></a>解题思路</h4><p>首先考虑 $c = 1$ 的情况.</p><p>首先可以观察到一个性质: 对于每一个节点, 除去最高位, 可通过其他位上 0 / 1 的区别, 我们可以确定该节点在不同层上选择左 / 右节点.</p><p>因此, 对于线段树上两个节点 $x$, $y$, 其在线段树上 LCA 为 $x$, $y$ 在二进制表示下, 将高位对齐得到的 LCP.</p><p>同时, 一个节点 $x$ 到根节点路径上编号和为 $2x - \operatorname{popcount}(x)$. 其中 $\operatorname{popcount}(x)$ 表示 $x$ 在二进制表示下 $1$ 的个数. 当然直接在线段树上暴力向上跳也可以.</p><p>简单证明一下, 考虑祖先中出现多出一次左儿子的影响, 体现在二进制表示下即某位改变为 $1$. 将多出的贡献单独拿出来计算, 等同于再次从根节点开始的贡献, 只不过深度改变了. 那么答案为 $2x - \operatorname{popcount}(x)$.</p><p>考虑 $c = 2$ 的情况.</p><p>记第一问求出的答案为 $s$, 有一个重要的性质: 设两节点 $x$, $y$ 的 LCA $z$, $z$ 到 $x$ 链长 $a$, 到 $y$ 链长 $b$. 如果 $a$, $b$, $s$ 确定, 那么 $z$ 的位置唯一.</p><p>简单证明一下. 不妨令 $x < y$. 同时记 $z$ 在二进制表示下有 $t$ 位, 那么 $x$ 在二进制表示下有 $t + a$ 位, $y$ 在二进制表示下有 $t + b$ 位.</p><p>先考虑 $x$, $y$ 前 $t$ 位路径编号和 $s$ 的贡献. 即</p><script type="math/tex; mode=display">\left(\sum_{i = 0} ^ a 2 ^ i + \sum_{i = 0} ^ b 2 ^ i - 1\right)\cdot z = \left( 2 ^ {a + 1} + 2 ^ {b + 1} - 3 \right) \cdot z</script><p>另外有 $x$ 后 $a$ 位, $y$ 后 $b$ 位的贡献. 考虑取最值的两种情况, 即在满足条件的情况下不断向左 / 右走, 可得最小值为 $2 ^ b - 1$, 最大值为 $\left(2 ^ a - 1 - a\right) + \left(2 ^ {b + 1} - 1 - b\right)$.</p><p>因此可将 $s$ 表示为 $s = vz + k$ 的形式, 其中 $v = 2 ^ {a + 1} + 2 ^ {b + 1} - 3$, $k \in [2 ^ b - 1, 2 ^ a + 2 ^ {b + 1} - a - b - 3]$. 从而有 $z = \lfloor \frac{s - k}{v} \rfloor$. 注意到 $k < v$, 因此 $z$ 和 $k$ 无关, $z$ 在 $a$, $b$ 确定后唯一.</p><p>此时枚举 $a$, $b$ 的取值, 求满足 $k = s - vz$ 的方案数即可. 根据前文的性质, 此时的问题可转化为, 给定一长为 $a - 1$ 的 0-1 串 $A$ 和一长为 $b$ 的 0-1 串 $B$, 求满足 $2A - \operatorname{popcount}(A) + 2B - \operatorname{popcount}(B) = k$ 的 $A$, $B$ 方案数.</p><p>DP 计算即可. 具体地, 首先枚举 $\operatorname{popcount}(A) + \operatorname{popcount}(B)$ 取值 $w$, 那么限制为 $2(A + B) = k + w$.</p><p>设 $f(i, j, k)$, $k \in \{0, 1\}$ 表示考虑前 $i$ 位, 共凑出 $j$ 个 $1$, 且当前位是否存在进位的方案数. 转移即为</p><script type="math/tex; mode=display">f(i, j + p + q, \lfloor \frac{p + q + k}{2} \rfloor) = \sum_{p,\ q} f(i - 1, j, k)</script><p>实现时需要注意, 要强制 $A$ 的第 $a$ 位为 $0$, 以及 $B$ 的第 $b$ 位为 $1$, 同时要满足 $A + B$ 二进制表示下每一位和 $\frac{1}{2}(k + w)$ 相同.</p><p>时间复杂度 $O(d ^ 5)$.</p><h4 id="代码实现-5"><a href="#代码实现-5" class="headerlink" title="代码实现"></a>代码实现</h4><div><div class="fold_hider"><div class="close hider_title">> 点击显示 / 隐藏 </div></div><div class="fold"><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// LOJ #3109</span></span><br><span class="line"><span class="comment">// DeP</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> LL;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXD = <span class="number">5e2</span> + <span class="number">5</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> d;</span><br><span class="line">LL f[MAXD << <span class="number">1</span>][MAXD << <span class="number">1</span>][<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> LL <span class="title">Dist</span><span class="params">(<span class="type">const</span> LL& x)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="number">2</span> * x - __builtin_popcountll(x);</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">inline</span> LL <span class="title">LCA</span><span class="params">(LL u, LL v)</span> </span>{</span><br><span class="line"> <span class="keyword">while</span> (u != v) {</span><br><span class="line"> <span class="keyword">if</span> (u < v) <span class="built_in">swap</span>(u, v);</span><br><span class="line"> u >>= <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> u;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">lg2</span><span class="params">(LL s)</span> </span>{</span><br><span class="line"> <span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> (s > <span class="number">0</span>) s >>= <span class="number">1</span>, ++ret;</span><br><span class="line"> <span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function">LL <span class="title">solve</span><span class="params">(<span class="type">const</span> LL& s, <span class="type">const</span> <span class="type">int</span>& c, <span class="type">const</span> <span class="type">int</span>& a, <span class="type">const</span> <span class="type">int</span>& b)</span> </span>{</span><br><span class="line"> <span class="type">int</span> limit = <span class="built_in">max</span>(<span class="built_in">lg2</span>(s), <span class="built_in">max</span>(a - <span class="number">1</span>, b));</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i <= limit; ++i)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j <= c; ++j) f[i][j][<span class="number">0</span>] = f[i][j][<span class="number">1</span>] = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> p = <span class="number">0</span>; p <= <span class="number">1</span>; ++p) {</span><br><span class="line"> <span class="keyword">if</span> (a <= <span class="number">1</span> && p == <span class="number">1</span>) <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> q = <span class="number">0</span>; q <= <span class="number">1</span>; ++q) <span class="keyword">if</span> (p + q <= c) {</span><br><span class="line"> <span class="keyword">if</span> (((p + q) & <span class="number">1</span>) != (s & <span class="number">1</span>)) <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">if</span> ((b < <span class="number">1</span> && q == <span class="number">1</span>) || (b == <span class="number">1</span> && q == <span class="number">0</span>)) <span class="keyword">continue</span>;</span><br><span class="line"> ++f[<span class="number">0</span>][p + q][(p + q) / <span class="number">2</span>];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i <= limit; ++i) <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j <= c; ++j)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">0</span>; k <= <span class="number">1</span>; ++k) <span class="keyword">if</span> (f[i - <span class="number">1</span>][j][k] > <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> p = <span class="number">0</span>; p <= <span class="number">1</span>; ++p) {</span><br><span class="line"> <span class="keyword">if</span> (i >= a - <span class="number">1</span> && p == <span class="number">1</span>) <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> q = <span class="number">0</span>; q <= <span class="number">1</span>; ++q) <span class="keyword">if</span> (j + p + q <= c) {</span><br><span class="line"> <span class="keyword">if</span> (((k + p + q) & <span class="number">1</span>) != ((s >> i) & <span class="number">1</span>)) <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">if</span> ((i > b - <span class="number">1</span> && q == <span class="number">1</span>) || (i == b - <span class="number">1</span> && q == <span class="number">0</span>)) <span class="keyword">continue</span>;</span><br><span class="line"> f[i][j + p + q][(k + p + q) / <span class="number">2</span>] += f[i - <span class="number">1</span>][j][k];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> f[limit][c][<span class="number">0</span>];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"input.in"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"> <span class="type">int</span> Ti, c;</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &Ti);</span><br><span class="line"> <span class="keyword">while</span> (Ti--) {</span><br><span class="line"> LL x, y;</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%lld%lld%d"</span>, &d, &x, &y, &c);</span><br><span class="line"> LL z = <span class="built_in">LCA</span>(x, y), s = <span class="built_in">Dist</span>(x) + <span class="built_in">Dist</span>(y) - <span class="built_in">Dist</span>(z) - <span class="built_in">Dist</span>(z >> <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">if</span> (c == <span class="number">1</span>)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%lld\n"</span>, s);</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> LL ans = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> a = <span class="number">0</span>; a < d; ++a)</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> b = <span class="number">0</span>; b < d; ++b) {</span><br><span class="line"> LL v = (<span class="number">1LL</span> << (a + <span class="number">1</span>)) + (<span class="number">1LL</span> << (b + <span class="number">1</span>)) - <span class="number">3</span>;</span><br><span class="line"> <span class="keyword">if</span> (v == <span class="number">0</span>) <span class="keyword">continue</span>;</span><br><span class="line"> z = s / v;</span><br><span class="line"> <span class="keyword">if</span> (z <= <span class="number">0</span> || <span class="built_in">lg2</span>(z) + <span class="built_in">max</span>(a, b) > d) <span class="keyword">continue</span>;</span><br><span class="line"> LL k = s - v * z;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i <= a + b; ++i)</span><br><span class="line"> <span class="keyword">if</span> ((k + i) % <span class="number">2</span> == <span class="number">0</span>) ans += <span class="built_in">solve</span>((k + i) / <span class="number">2</span>, i, a, b);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%lld\n"</span>, ans - <span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></div></div><hr>]]></content>
<summary type="html"><hr>
<p><del>我没有在刷水题 (确信</del></p>
<p>打 扰 了.</p></summary>
<category term="题解" scheme="https://depletedprism.github.io/categories/%E9%A2%98%E8%A7%A3/"/>
</entry>
</feed>