-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.xml
More file actions
2287 lines (2266 loc) · 169 KB
/
search.xml
File metadata and controls
2287 lines (2266 loc) · 169 KB
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
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>【目录】博客索引</title>
<url>/2023/10/08/%E3%80%90%E7%9B%AE%E5%BD%95%E3%80%91/</url>
<content><![CDATA[<p><strong>待施工ing</strong></p>
<span id="more"></span>
]]></content>
<categories>
<category>索引</category>
</categories>
<tags>
<tag>QwQ</tag>
</tags>
</entry>
<entry>
<title>HashKiller——如何优雅地卡掉单模数哈希</title>
<url>/2024/03/19/HashKiller%E2%80%94%E2%80%94%E5%A6%82%E4%BD%95%E4%BC%98%E9%9B%85%E5%9C%B0%E5%8D%A1%E6%8E%89%E5%8D%95%E6%A8%A1%E6%95%B0%E5%93%88%E5%B8%8C/</url>
<content><![CDATA[<h2 id="i.-起因">I. 起因</h2>
<p>之前打比赛多次担心写单哈希被卡,但 N
神之前说他高中打过的所有比赛,但凡是字符串的题写 unsigned long long
自然溢出从来没被卡过。我信以为真,认为现在已经没有人素质差到卡别人单模哈希。后来我打了一些
AtCoder 的比赛也写了很多 ull 自然溢出也没事。直到 <a
href="https://codeforces.com/contest/1943">这场CF</a> N 神 B 题 ull
自然溢出被卡到裂开,以为思路错了,直到赛后才发现是单哈希被卡了。</p>
<span id="more"></span>
<p>鉴于以上惨痛的经历,我决定学习一下毒瘤的卡单模数哈希的方法,来警示自己以及与
N
神心态类似的人:不要管出题人卡不卡,反正写双哈希就对了。<del>(警钟撅烂(逃</del></p>
<h2 id="ii.-模-109-级别的大质数哈希">II. 模 <span
class="math inline">\(10^9\)</span> 级别的大质数哈希</h2>
<p>其实单模 <span class="math inline">\(10^9\)</span>
级别的大质数哈希非常好卡,我们只需要随机一个长度为 <span
class="math inline">\(10^5\)</span> 级别的只包含小写字母的字符串 <span
class="math inline">\(s\)</span>,再任取一个大小为 <span
class="math inline">\(100\)</span> 左右的子串长度 <span
class="math inline">\(k\)</span>,那么 <span
class="math inline">\(s\)</span> 的所有长度为 <span
class="math inline">\(k\)</span>
的子串中大概率会存在哈希冲突的字符串。</p>
<p>那么概率到底有多大呢,我们可以使用<strong>生日悖论</strong>的方法来计算。</p>
<p>字符串 <span class="math inline">\(s\)</span> 的长度为 <span
class="math inline">\(k\)</span> 的子串总共有 <span
class="math inline">\(26^{k}\)</span> 种可能,当 <span
class="math inline">\(k = 100\)</span> 时 <span
class="math inline">\(s\)</span> 的任意两个长度为 <span
class="math inline">\(k\)</span>
的子串几乎不可能相等,所以我们按照长度为 <span
class="math inline">\(k\)</span>
的子串均不同来考虑。(其实计算这个本身也是生日悖论)</p>
<p>因为 <span class="math inline">\(s\)</span> 中总共有 <span
class="math inline">\(10^5 - k + 1\)</span> 个长度为 <span
class="math inline">\(k\)</span> 的子串,设 <span
class="math inline">\(p\)</span> 为模数,则第 <span
class="math inline">\(1\)</span> 个子串的哈希值不跟之前重复的概率为
<span class="math inline">\(\displaystyle{\frac{p}{p}}\)</span>,第
<span class="math inline">\(2\)</span>
个子串的哈希值不跟之前重复的概率为 <span
class="math inline">\(\displaystyle{\frac{p - 1}{p}}\)</span> ,第 <span
class="math inline">\(n\)</span> 个子串的哈希值不跟之前重复的概率为
<span class="math inline">\(\displaystyle{\frac{p - n +
1}{p}}\)</span>。所以出现至少两个长度为 <span
class="math inline">\(k\)</span> 子串哈希冲突的概率为 <span
class="math inline">\(\displaystyle{1 - \prod\limits_{i = 1}^{10^{5} - k
+ 1} \frac{p - i + 1}{p}}\)</span>。当 <span class="math inline">\(p =
10^9 + 7, k = 100\)</span> 时计算上式的值约为 <span
class="math inline">\(0.9931958400\)</span>。</p>
<p>根据以上结论,随便写个代码一随机就能找到两个哈希冲突的字符串,所以单模
<span class="math inline">\(10^9\)</span> 级别的哈希千万不要写。</p>
<h2 id="iii.-unsigned-long-long-自然溢出哈希">III. unsigned long long
自然溢出哈希</h2>
<p>由于样本空间是 <span class="math inline">\(10^{18}\)</span>
级别,非常大,直接采取<strong>生日悖论</strong>的方法难以卡掉。</p>
<p>其实我们用上面的方法算一下概率,取 <span class="math inline">\(p =
10^{18}\)</span>,<span class="math inline">\(|s| =
10^{6}\)</span>,<span class="math inline">\(k =
100\)</span>,哈希冲突的概率约为 <span
class="math inline">\(0.0000004999\)</span>。(这其实也为两个 <span
class="math inline">\(10^{9}\)</span>
级别大质数的双模哈希的正确性提供了证明。)</p>
<p>所以我们要换一套方法来卡,这里一般的方法为构造法。</p>
<h3 id="对于底数为偶数的情况">1. 对于底数为偶数的情况</h3>
<p>构造字符串 <code>baaa...</code>(后面有 <span
class="math inline">\(64\)</span> 个 <code>a</code>)与
<code>caaa...</code>(后面有 <span class="math inline">\(64\)</span> 个
<code>a</code>)即可卡掉。</p>
<p>这两个字符串的后 <span class="math inline">\(64\)</span> 个字符均为
<code>a</code>,所以只需要关心第 <span class="math inline">\(1\)</span>
个位置对哈希值的贡献。</p>
<p>对于第一个字符串,第 <span class="math inline">\(1\)</span>
个位置对哈希值的贡献为 <span
class="math inline">\(H(\text{"b"}) \times Base^{64} \bmod
2^{64}\)</span>。</p>
<p>对于第二个字符串,第 <span class="math inline">\(1\)</span>
个位置对哈希值的贡献为 <span
class="math inline">\(H(\text{"a"}) \times Base^{64} \bmod
2^{64}\)</span>。</p>
<p>因为 <span class="math inline">\(Base\)</span> 为偶数,所以 <span
class="math inline">\(Base\)</span> 中至少含有一个因子 <span
class="math inline">\(2\)</span>,所以 <span
class="math inline">\(2^{64} \mid Base^{64}\)</span>,所以两个字符串的第
<span class="math inline">\(1\)</span> 个位置对哈希值的贡献均为 <span
class="math inline">\(0\)</span>,所以两字符串哈希冲突。</p>
<h3 id="对于底数为奇数的情况">2. 对于底数为奇数的情况</h3>
<p>考虑进行如下构造:</p>
<ul>
<li>定义 <span class="math inline">\(S_1 =
\text{"a"}\)</span></li>
<li>令 <span class="math inline">\(\text{len}(S_i)\)</span> 表示字符串
<span class="math inline">\(S_i\)</span> 的长度</li>
<li>令 <span class="math inline">\(\text{not}(T)\)</span> 为将字符串
<span class="math inline">\(T\)</span> 中字符 <span
class="math inline">\(\text{"a"}\)</span> 变为字符 <span
class="math inline">\(\text{"b"}\)</span>,字符 <span
class="math inline">\(\text{"b"}\)</span> 变为字符 <span
class="math inline">\(\text{"a"}\)</span> 的函数</li>
<li><span class="math inline">\(S_i = S_{i - 1} + \text{not}(S_{i -
1})\)</span></li>
</ul>
可以推导出 <span class="math inline">\(\text{len}(S_i) = 2^{i -
1}\)</span>,且 $$
<span class="math display">\[\begin{aligned}
&H(S_i) = H(S_{i - 1}) \times Base^{2^{i - 1}} + H(\text{not}(S_{i -
1})) \\
&H(\text{not}(S_i)) = H(\text{not}(S_{i - 1})) \times Base^{2^{i -
1}} + H(S_{i - 1})
\end{aligned}\]</span>
<p><span class="math display">\[
令 $f_i = H(S_i) - H(\text{not}(S_{i - 1}))$,上述两式相减,可得
\]</span> f_{i} = f_{i - 1} (Base<sup>{2</sup>{i-1}} - 1) $$ 当 <span
class="math inline">\(f_i \bmod 2^{64} = 0\)</span>
时,我们即可构造出两个哈希冲突的字符串。</p>
<p>注意到 <span class="math inline">\(Base\)</span> 为奇数,所以 <span
class="math inline">\(Base^{2^{i - 1}} - 1\)</span> 必定为偶数。所以
<span class="math inline">\(f_{64} \bmod 2^{64}\)</span> 必定为 <span
class="math inline">\(0\)</span>,但是这要构造出两个长度为 <span
class="math inline">\(2^{63}\)</span> 的字符串 <span
class="math inline">\(S_{64}\)</span> 和 <span
class="math inline">\(\text{not}(S_{64})\)</span>,理论上这两个串是哈希冲突的,但是因为长度太长,现实中显然无法进行读写。</p>
<p>注意到 <span class="math inline">\((Base^{2^{i - 1}} - 1) =
(Base^{2^{i - 2}} + 1)(Base^{2^{i-2}} - 1) = (Base^{2^{i - 2}} +
1)(Base^{2^{i - 3}} + 1) \cdots (Base^{2^{1}} + 1)(Base^{2^{1}} -
1)\)</span>。容易证明,上述的每一项都是偶数,所以 <span
class="math inline">\(f_i\)</span> 中至少含有 <span
class="math inline">\((i - 1) + (i - 2) + \cdots + 1 =
\displaystyle{\frac{(i - 1)i}{2}}\)</span> 个因子 <span
class="math inline">\(2\)</span>。</p>
<p>由上述理论进行计算,<span class="math inline">\(f_{12}\)</span>
中至少含有 <span class="math inline">\(66\)</span> 个因子 <span
class="math inline">\(2\)</span>,所以 <span
class="math inline">\(S_{12}\)</span> 与 <span
class="math inline">\(\text{not}(S_{12})\)</span> 哈希冲突,长度仅为
<span class="math inline">\(2^{11}\)</span>。</p>
<h2 id="iv.-小结">IV. 小结</h2>
<p>至此,不管如何更换模数和进制,常见的单模哈希的所有情况均被上述算法卡掉。</p>
<p>所以<strong>一定要写双模!!!一定要写双模!!!一定要写双模!!!双模一定要改模数,不要只改进制!!!</strong></p>
]]></content>
<categories>
<category>一些毒瘤</category>
</categories>
<tags>
<tag>哈希</tag>
</tags>
</entry>
<entry>
<title>NEUQ-ACM 预备队&竞赛队寒假集训刷题小记</title>
<url>/2024/01/21/%E3%80%90%E6%9D%82%E9%A2%98%E3%80%91NEUQ%20ACM%20%E9%A2%84%E5%A4%87%E9%98%9F%E5%AF%92%E5%81%87%E9%9B%86%E8%AE%AD%E5%88%B7%E9%A2%98%E5%B0%8F%E8%AE%B0/</url>
<content><![CDATA[<h2 id="brief">Brief</h2>
<p>NEUQ 寒假集训自主刷题记录,比较 trivival
会简记一下思路,比较困难会写解题报告或者题解记录一下。</p>
<span id="more"></span>
<p><span class="math inline">\(\textcolor{grey}{\bigstar}\)</span>
表示思维难度偏低、且各方面比较普通或比较套路的题(不考虑使用的算法)。</p>
<p><span class="math inline">\(\textcolor{green}{\bigstar}\)</span>
表示整体难度一般甚至偏低、但思考过程或结论可能具有启发性的小清新题目。</p>
<p><span class="math inline">\(\textcolor{brown}{\bigstar}\)</span>
表示思维难度中等的中档题。</p>
<p><span class="math inline">\(\textcolor{blue}{\bigstar}\)</span>
表示需要较高思维难度、思考过程或结论很具有启发性的题目。</p>
<p><span class="math inline">\(\textcolor{magenta}{\bigstar}\)</span>
表示需要一定知识基础和相关进阶算法的题。</p>
<p><span class="math inline">\(\textcolor{red}{\bigstar}\)</span>
表示思考了一段时间,但思考过程不完整,思路没有到位或只有部分正确,最终看题解才做出来的题。(最需要练习的题目)</p>
<h2 id="section"><strong>1.15</strong></h2>
<p>做题之余,整体复习了一下数论,稍微学习了一下二次剩余和离散对数。</p>
<p><strong>题目 <span class="math inline">\(01\)</span> :</strong><a
href="https://atcoder.jp/contests/abc336/tasks/abc336_f">ABC336F -
Rotation Puzzle</a> <span
class="math inline">\(\textcolor{grey}{\bigstar}\textcolor{magenta}{\bigstar}\)</span>
<strong>[折半(搜索)思想]</strong></p>
<p><strong>思路:</strong>考虑进行四进制状压,<span
class="math inline">\(0,1,2,3\)</span>
分别代表左上、右上、左下和右下的旋转,但是有 <span
class="math inline">\(4^{20}\)</span>
种枚举状态。注意到最终状态是确定的,而且旋转操作可逆,那就可以采取折半搜索的方法,从起始状态枚举
<span class="math inline">\(10\)</span>
步,把状态存到哈希表中,再从末状态枚举 <span
class="math inline">\(10\)</span> 步,再从哈希表中查找,这样就只需要枚举
<span class="math inline">\(4^{10} = 2^{20}\)</span>
种状态了。假设上限步数为 <span class="math inline">\(n\)</span>
,则时间复杂度为 <span class="math inline">\(O(2^{n}nHW)\)</span> ,取
<span class="math inline">\(n = 20\)</span> 即可。</p>
<p><strong>题目 <span class="math inline">\(02\)</span> :</strong> <a
href="https://atcoder.jp/contests/abc335/tasks/abc335_f">ABC335F - Hop
Sugoroku</a> <span
class="math inline">\(\textcolor{grey}{\bigstar}\textcolor{magenta}{\bigstar}\)</span>
<strong>[根号分治]</strong></p>
<p><strong>思路:</strong>设 <span class="math inline">\(f_i\)</span>
代表以 <span class="math inline">\(i\)</span> 为结尾且 <span
class="math inline">\(i\)</span> 被涂黑的方案数,不难发现 <span
class="math inline">\(f\)</span> 的转移可以根据 <span
class="math inline">\(a_i\)</span> 的大小进行根号分治。如果 <span
class="math inline">\(a_i \ge \sqrt{n}\)</span> ,直接暴力每次跳 <span
class="math inline">\(a_i\)</span> 进行转移,如果 <span
class="math inline">\(a_i < \sqrt{n}\)</span> ,因为从 <span
class="math inline">\(i\)</span> 能跳到的所有位置 <span
class="math inline">\(p \bmod a_i\)</span> 一定等于 <span
class="math inline">\(i \bmod a_i\)</span>
,所以可以直接开一个二维数组记录模 <span
class="math inline">\(x\)</span> 等于 <span
class="math inline">\(y\)</span> 的位置上被加的贡献。时间复杂度为 <span
class="math inline">\(O(n\sqrt{n})\)</span> 。</p>
<h2 id="section-1"><strong>1.16</strong></h2>
<p>研究一个与离散对数有关的题,还没研究出来,然后上午 <span
class="math inline">\(11\)</span> 点的时候被叫去给预备队出题,然后花了
<span class="math inline">\(2.5\text{h}\)</span> 跟 ljc 和 zyb
搞了一套入门级别的题,然后下午的时候激情看榜(出了好多锅,甚至 <span
class="math inline">\(\text{B}\)</span>
题的数据还锅了,成为背锅人),最后一起写了<a
href="https://www.luogu.com.cn/blog/BrotherCall/neuq-acm-han-jia-ji-xun-huan-le-sai-1-guan-fang-ti-xie">题解</a>。</p>
<p>晚上继续研究那道题,最后终于搞明白了。近期准备写一个数论学习总结。</p>
<p><strong>题目 <span class="math inline">\(\text{03}\)</span>
:</strong> <a
href="https://atcoder.jp/contests/abc335/tasks/abc335_g">ABC335G -
Discrete Logarithm Problems</a> <span
class="math inline">\(\textcolor{blue}{\bigstar}\textcolor{magenta}{\bigstar}\textcolor{red}{\bigstar}\)</span>
<strong>[阶 | 原根 | 离散对数]</strong></p>
<p><strong>思路:</strong><a
href="https://tle-automat.top/2024/01/17/ABC335G/">【题解】ABC335G</a>。</p>
<p>搞完这个题之后,听 zyb 说了说<a
href="https://codeforces.com/contest/1921">昨晚 div.3</a>的 G
题,发现题有点怪,但做法很一般,那就口胡一个题解。</p>
<p><strong>题目 <span class="math inline">\(\text{04}\)</span>
:</strong><a
href="https://codeforces.com/contest/1921/problem/G">CF1921G -
Mischievous Shooter</a> <span
class="math inline">\(\textcolor{brown}{\bigstar}\)</span> <strong>[递推
| 二维前缀和]</strong></p>
<p><strong>思路:</strong>这题看着听唬人,实际上不太难想,只需要采取最普通的思路,只需要维护一下每行、每列、左斜线和右斜线的前缀和,四个方向都要跑一下类似于二维前缀和的递推,推出以每个点为端点,距离这个端点曼哈顿距离
<span class="math inline">\(\le k\)</span> 的方格的和即可,时间复杂度
<span
class="math inline">\(O(nm)\)</span>。但是边界啥的懒得想了,感觉稍微有些难写。</p>
<p>又听 zyb 说了昨晚 div.3 的 F
题,据说是根号分治,但想了半天没想出来其中一边怎么分,所以打算明天研究一下。</p>
<h2 id="section-2"><strong>1.17</strong></h2>
<p>上午写昨天的没搞完的 ABC335G
的题解,然后发现一个关键证明锅了,然后又花了一上午研究才彻底通透。</p>
<p>中午的时候博客出锅了,修了修 Blog,发现 hexo-renderer-kramed 和
hexo-renderer-marked 引擎渲染行间公式的时候
<code>$$</code>的转义有问题,离大谱。</p>
<p>下午听学长讲了几个构造题,挺有意思的,因为没有地方测也没有写,所以就不作为正式题目了。</p>
<p>一个是 lbf
学长自己想的跟俄罗斯方块有关的构造,给定一个初始局面,给一些面积为 <span
class="math inline">\(4\)</span>
的块,要求构造一些下落的方块之后回到初始局面,保证宽为偶数。想一想发现只需要开始时在最高的地方整一个反着的
<span class="math inline">\(\text{T}\)</span>
字,然后向两端铺㇅字,之后再随机应变向上填充,刚好能填充满 <span
class="math inline">\(4\)</span> 行。</p>
<p>另外一个是 <span class="math inline">\(\text{ec final}\)</span>
的一个题。就是给定两个 <span class="math inline">\(01\)</span> 串 <span
class="math inline">\(A\)</span> 和 <span
class="math inline">\(B\)</span> ,保证两个串的首位都是 <span
class="math inline">\(1\)</span> ,每次可以把 <span
class="math inline">\(A\)</span>
的一个区间去掉前导零后看作三进制,然后转化成二进制再填回去,平均每位不超过
<span class="math inline">\(8\)</span> 步把 <span
class="math inline">\(A\)</span> 构造成 <span
class="math inline">\(B\)</span>
。因为可以去掉前导零,所以只需要花费很少的步数把 <span
class="math inline">\(A\)</span> 串变成全 <span
class="math inline">\(1\)</span> ,然后考虑怎么把全 <span
class="math inline">\(1\)</span> 串变成 <span
class="math inline">\(B\)</span>。因为 <span
class="math inline">\((11)_{3} = (100)_2\)</span> ,<span
class="math inline">\((10)_3 = (11)_2\)</span> ,所以假设 <span
class="math inline">\(B\)</span> 中有 <span
class="math inline">\(x\)</span> 个 <span
class="math inline">\(1\)</span> ,那只需要把 <span
class="math inline">\(A\)</span> 先变成连续的 <span
class="math inline">\(2x\)</span> 个 <span
class="math inline">\(1\)</span> ,这样每次修改连续的 <span
class="math inline">\(2\)</span> 个 <span
class="math inline">\(1\)</span> ,比如 <span class="math inline">\(11
\rightarrow 100 \rightarrow 110 \rightarrow 1000\)</span> ,即可实现把
<span class="math inline">\(11\)</span> 变成 <span
class="math inline">\(1\)</span> 加上任意多个 <span
class="math inline">\(0\)</span> ,步数很少,目测是足够的。</p>
<p>晚上研究了一下昨天说的哪个 div.3 F
题,发现自己被卡在了如何优美的定义数组上,遂记之。</p>
<p><strong>题目 <span class="math inline">\(\text{05}\)</span>
:</strong> <a
href="https://codeforces.com/contest/1921/problem/F">CF1921F - Sum of
Progression</a> <span
class="math inline">\(\textcolor{brown}{\bigstar}\textcolor{magenta}{\bigstar}\)</span>
<strong>[根号分治]</strong></p>
<p><strong>思路:</strong>我感觉这题的难度不在于想到根号分治,其实根号分治比较一眼,我被卡在了一个奇怪的地方。当
<span class="math inline">\(d \ge \sqrt{n}\)</span>
的时候显然直接暴力跳即可。当 <span class="math inline">\(d <
\sqrt{n}\)</span> 的时候,可以预处理。具体的,枚举每一个步长 <span
class="math inline">\(d\)</span> ,再枚举起点 <span
class="math inline">\(st\)</span> ,然后挨着跳,预处理前缀和与 <span
class="math inline">\(\sum k \cdot a _{(k - 1)d + st}\)</span>
的前缀和,这样做的时间复杂度为 <span
class="math inline">\(O\left(\sum_{d = 1}^{\sqrt{n}} d \cdot
\displaystyle\frac{n}{d}\right) =
O(n\sqrt{n})\)</span>。但这样问题就出在预处理的数组要开 <span
class="math inline">\(3\)</span> 维,第一维存步长 <span
class="math inline">\(d\)</span>,第二维存起点 <span
class="math inline">\(st\)</span>,第三维存跳到哪儿了,因为数组没办法根据不同的
<span class="math inline">\(d\)</span> 给 <span
class="math inline">\(st\)</span>
开不同的长度,所以空间必须全都开满,所以空间复杂度就是 <span
class="math inline">\(O(\sqrt{n} \cdot\sqrt{n} \cdot n) =
O(n^{2})\)</span> 就炸了。但其实仔细想想没有必要开 <span
class="math inline">\(3\)</span> 维,因为只要确定当前跳到的位置 <span
class="math inline">\(p\)</span> ,和步长 <span
class="math inline">\(d\)</span> ,其他能跳到的位置可以通过 <span
class="math inline">\(p + kd\)</span>
计算得出,起点自然就确定了,所以只需要开二维数组预处理即可,剩下的就没有难度了。</p>
<h2 id="section-3">1.18</h2>
<p>今天上午跟出题组其他人一起准备了下午的预备队天梯赛 <span
class="math inline">\(1\)</span> 的题,并且写了题解。</p>
<p>简要在这里写一下<a
href="https://acjudge.com/d/northstarcup/p/151">我搬的那题</a>的题解:由勾股定理
<span class="math inline">\(a^{2} = c^{2} - b^{2} = (c + b)(c -
b)\)</span>,这启示我们去找 <span class="math inline">\(a^{2}\)</span>
的约数。将 <span class="math inline">\(a\)</span> 进行质因数分解有 <span
class="math inline">\(a = p_{1}^{k_1} p_{2}^{k_2} \cdots
p_{m}^{k_m}\)</span>,则 <span class="math inline">\(a^{2} =
p_{1}^{2k_1} p_{2}^{2k_2} \cdots
p_{m}^{2k_m}\)</span>,这一步的时间复杂度为 <span
class="math inline">\(O(\sqrt{a})\)</span>。考虑通过 <span
class="math inline">\(a^{2}\)</span> 的唯一分解,dfs
每一个质因数的指数,不重不漏地枚举 <span
class="math inline">\(a^{2}\)</span> 的约数。通过这个网站 <a
href="https://oeis.org/A066150">https://oeis.org/A066150</a> ,我们得知
<span class="math inline">\(10^{24}\)</span>
以内因数个数最多的数的因数个数是 <span
class="math inline">\(1290240\)</span>,所以时间复杂度可以保证,数学巨神
wrx 也给出了一个很严格的上界 <span
class="math inline">\(\operatorname{d}(n) < n^{\frac{1.066}{\ln\ln
n}}\)</span>,通过这个也可以粗略计算 <span
class="math inline">\(10^{24}\)</span> 以内的数的因数个数最大是 <span
class="math inline">\(10^6\)</span>
级别。枚举约数的时候,顺便判断一下能否写成 <span
class="math inline">\(a^{2} = (c + b)(c - b)\)</span> 的形式即可,其中
<span class="math inline">\(a < b < c\)</span>。</p>
<p>下午写题,晚上打了一场 <a
href="https://codeforces.com/contest/1922">Edu div.2</a>,<span
class="math inline">\(6\)</span> 题过了 <span
class="math inline">\(5\)</span>
题,但罚时吃满了,预测上不了紫,希望不要 fst ,A 到 E 都挺简单,D
细节有点多,E 题好像还是原题。简记一下 D 和 E。</p>
<p><strong>题目 <span class="math inline">\(\text{06}\)</span>
:</strong><a
href="https://codeforces.com/contest/1922/problem/D">CF1922D - Berserk
Monsters</a> <span
class="math inline">\(\textcolor{grey}{\bigstar}\)</span> <strong>[模拟
| 链表]</strong></p>
<p><strong>思路:</strong>考虑每个怪最多只会死一次,维护一个链表,里面是当前活着的怪。维护两个
vector
分别代表这轮要寄的和下轮要寄的,每轮遍历一下这轮要寄的从链表中删除,然后更新一下下轮要寄的即可。</p>
<p><strong>题目 <span class="math inline">\(\text{07}\)</span>
:</strong><a
href="https://codeforces.com/contest/1922/problem/E">CF1922E -
Increasing Subsequences</a> <span
class="math inline">\(\textcolor{green}{\bigstar}\)</span> <strong>[构造
| 二进制]</strong></p>
<p><strong>思路:</strong>考虑将 <span class="math inline">\(x\)</span>
二进制分解,假设最高位为第 <span class="math inline">\(dig\)</span>
位,那么先构造一个长度为 <span class="math inline">\(dig\)</span>
的上升序列 <span class="math inline">\(h\)</span>,这样一开始的贡献是
<span class="math inline">\(2^{dig}\)</span> 。之后从高到低遍历 <span
class="math inline">\(x\)</span> 的其他位,如果第 <span
class="math inline">\(i\)</span> 位是 <span
class="math inline">\(1\)</span> ,那么在后面加一个介于 <span
class="math inline">\(h_i\)</span> 和 <span class="math inline">\(h_{i +
1}\)</span> 之间的数,这样产生的新的贡献就是 <span
class="math inline">\(2^{i}\)</span> ,这样最多需要 <span
class="math inline">\(60 + 60 = 120\)</span> 位就够了。</p>
<p><strong>题目 <span class="math inline">\(\text{08}\)</span>
:</strong><a
href="https://atcoder.jp/contests/abc334/tasks/abc334_f">ABC334F -
Christmas Present 2</a> <span
class="math inline">\(\textcolor{grey}{\bigstar}\)</span>
<strong>[动态规划 | 单调队列]</strong></p>
<p><strong>思路:</strong>考虑 <span
class="math inline">\(f_{i}\)</span> 代表送到第 <span
class="math inline">\(i\)</span> 的点然后回家的最小代价,因为一次最多拿
<span class="math inline">\(k\)</span> 个礼物,所以这个 dp
显然有类似滑动窗口的转移,跑一个前 <span
class="math inline">\(i\)</span>
个点的距离的前缀和预处理转移需要的代价,然后用单调队列优化即可。</p>
<p><strong>题目 <span class="math inline">\(\text{09}\)</span>
:</strong> <a
href="https://atcoder.jp/contests/abc334/tasks/abc334_g">ABC334G -
Christmas Color Grid 2</a> <span
class="math inline">\(\textcolor{grey}{\bigstar}\textcolor{magenta}{\bigstar}\)</span>
<strong>[点双连通分量 | 圆方树]</strong></p>
<p><strong>思路:</strong>考虑跑个点双,建出圆方树,然后每个统计每个圆点周围的方点个数,设为
<span class="math inline">\(x\)</span>
。那么删除这个圆点会导致连通块个数增加 <span class="math inline">\(x -
1\)</span> ,但是有一种特殊情况,就是只有一个圆点连接着 <span
class="math inline">\(0\)</span>
个方点,这样删除这个圆点会让连通块个数减 <span
class="math inline">\(1\)</span> 。用 tarjan
跑一下点双,剩下的期望随便算算就行了。</p>
<h2 id="section-4">1.19</h2>
<p>昨晚 CF 打完太兴奋了,然后打农和刷 B 站,凌晨 <span
class="math inline">\(3\)</span> 点才睡,第二天很晚才到 <span
class="math inline">\(\text{9028}\)</span>
训练,直接摆了一天,口胡了几个想补的题,完全不想写,明天再写吧(逃。</p>
<h2 id="section-5">1.20</h2>
<p>补了一下前天晚上 Edu 的 F 题,晚上打了场 ABC,结果 E 题最后 <span
class="math inline">\(n\)</span> 忘记加 <span
class="math inline">\(1\)</span>,一直找不到什么错,心态卡崩了,浪费了很多时间。而且长时间疏于数据结构,导致可持久化线段树已经忘得差不多了,粘板子改的也非常慢,最后
G 也没写完/kk/kk/kk。</p>
<p><strong>题目 <span class="math inline">\(10\)</span> :</strong><a
href="https://codeforces.com/contest/1922/problem/F">CF1922F - Replace
on Segment</a> <span
class="math inline">\(\textcolor{brown}{\bigstar}\textcolor{red}{\bigstar}\)</span>
<strong>[区间dp]</strong></p>
<p><strong>思路:</strong> 考虑区间 dp。设 <span
class="math inline">\(f_{i, j, x}\)</span> 表示把区间 <span
class="math inline">\([i, j]\)</span> 上的数全部变成 <span
class="math inline">\(x\)</span>
的最小代价。考虑转移,发现分为两种情况。第一种是将区间分为至少两端分别变成
<span class="math inline">\(x\)</span> ,这种情况可以通过 <span
class="math inline">\(f_{i, j, x} = \min\limits_{k = i}^{j -
1}\{f_{i,k,x} + f_{k+1, j, x}\}\)</span>
进行转移。第二种是先操作一些区间,最后将 <span class="math inline">\([i,
j]\)</span> 整体一次变成 <span class="math inline">\(x\)</span>
,但这种情况要求先通过前面的操作将区间 <span class="math inline">\([i,
j]\)</span> 的所有数变成非 <span class="math inline">\(x\)</span>
的数,思考一下可以发现,去掉 <span class="math inline">\([i, j]\)</span>
上等于 <span class="math inline">\(x\)</span>
的数的代价最小的方案,一定是一段一段地用数字覆盖。考虑令 <span
class="math inline">\(g_{i, j, x}\)</span> 表示将区间 <span
class="math inline">\([i, j]\)</span> 整体变成一个数 <span
class="math inline">\(y\)</span>,使得 <span class="math inline">\(y
\neq x\)</span> 的最小代价,这个可以通过 <span
class="math inline">\(f\)</span> 轻松推出。考虑取出区间 <span
class="math inline">\([i, j]\)</span> 上所有 <span
class="math inline">\(a_p = x\)</span> 的位置,令 <span
class="math inline">\(h_r\)</span> 表示前 <span
class="math inline">\(r\)</span> 个位置均被覆盖成非 <span
class="math inline">\(x\)</span> 的数的最小代价,有转移 <span
class="math inline">\(h_r = \min\limits_{l = 1} ^{r} \{h_{l - 1} +
g_{pos_{l},pos_{r},x}\} , f_{i, j, x} \leftarrow
h_{\operatorname{cnt}(x)} + 1\)</span>,<span
class="math inline">\(\operatorname{cnt}(x)\)</span> 表示区间 <span
class="math inline">\([i, j]\)</span> 上 <span
class="math inline">\(x\)</span>
的个数。还剩最后一个问题,这样的总复杂度转移看似是 <span
class="math inline">\(O(Tn^{5})\)</span> 的,因为除去枚举区间的 <span
class="math inline">\(O(n^{2})\)</span>,还有 <span
class="math inline">\(O(n^{3 })\)</span>
的转移。其实分析一下每一个位置对于复杂度的贡献发现 <span
class="math inline">\(O\left(\sum\limits_{i = 1}^{n}
[\operatorname{cnt}(i)]^{2}\right) =
O(n^{2})\)</span>,所以枚举完区间之后的转移实际上是 <span
class="math inline">\(O(n^{2})\)</span>,所以总复杂度是 <span
class="math inline">\(O(Tn^{4})\)</span>,卡满是 <span
class="math inline">\(5 \times 10^{8}\)</span>,但循环完全跑不满,而且有
<span class="math inline">\(3\text{s}\)</span>
的时限,可以通过,实际上最慢的只跑了 <span
class="math inline">\(600\text{ms}\)</span> 左右。(这里 <span
class="math inline">\(n\)</span> 和 <span
class="math inline">\(X\)</span> 同阶,不做区分)</p>
<p><strong>题目 <span class="math inline">\(11\)</span> :</strong><a
href="https://atcoder.jp/contests/abc337/tasks/abc337_g">ABC337G - Tree
Inversion</a> <span
class="math inline">\(\textcolor{brown}{\bigstar}\textcolor{magenta}{\bigstar}\)</span>
<strong>[树形dp | 换根dp | 主席树]</strong></p>
<p><strong>思路:</strong>考虑先 dfs 一遍,开个树状数组,把结点 <span
class="math inline">\(1\)</span>
的答案算出来,然后考虑换根时贡献的改变。考虑从 <span
class="math inline">\(fa\)</span> 换到 <span
class="math inline">\(u\)</span> ,假设 <span
class="math inline">\(v\)</span> 在 <span
class="math inline">\(u\)</span> 的子树内部,那么所有 <span
class="math inline">\(fa\)</span> 到 <span
class="math inline">\(v\)</span> 的路径上 <span class="math inline">\(w
= fa\)</span> 的贡献都要减掉,即减去 <span
class="math inline">\(u\)</span> 的子树内结点编号小于 <span
class="math inline">\(fa\)</span> 的结点的个数。同理,贡献还要加上 <span
class="math inline">\(u\)</span> 的子树外结点编号小于 <span
class="math inline">\(u\)</span> 的结点的个数。直接预处理出树的 dfs
序,每次换根相当于查询一个区间有多少个数小于 <span
class="math inline">\(k\)</span>,因为没有修改所以是静态的查询,直接用主席树处理即可。(以后有时间一定把数据结构封装一个模板)</p>
<h2 id="section-6">1.21</h2>
<p>昨天晚上因为 E 题忘记写 <span class="math inline">\(n + 1\)</span>
卡了 <span class="math inline">\(40\text{min}\)</span>
心态崩了,打农打到特别晚,因此第二天起的特别晚,摆了一天,F
题处于一种一知半解的状态,然后打了晚上的 ARC。C
题是一个很天才的套路,但我不知道,看题解知道了这个套路,遂记之。</p>
<p><strong>题目 <span class="math inline">\(12\)</span> :</strong><a
href="https://atcoder.jp/contests/arc170/tasks/arc170_c">ARC170C -Prefix
Mex Sequence</a> <span
class="math inline">\(\textcolor{blue}{\bigstar}\textcolor{red}{\bigstar}\)</span>
<strong>[dp]</strong></p>
<p><strong>思路:</strong>如果这题思路一直限制在 <span
class="math inline">\(\operatorname{mex}\)</span>
上,那么可能很难回到正轨了。首先注意到前 <span class="math inline">\(i -
1\)</span> 数的 <span class="math inline">\(\text{mex}\)</span> 的最大为
<span class="math inline">\(i\)</span>,所以直接枚举 <span
class="math inline">\(\text{mex}\)</span> 是 <span
class="math inline">\(O(\min(n, m))\)</span> 级别的,那假设我们设 <span
class="math inline">\(f_{i, j}\)</span> 代表前 <span
class="math inline">\(i\)</span> 个数的 <span
class="math inline">\(\text{mex}\)</span> 为 <span
class="math inline">\(j\)</span> 且符合题目条件的方案数,发现 <span
class="math inline">\(s_{i + 1} = 1\)</span> 时下一个状态的 <span
class="math inline">\(\text{mex}\)</span>
我们无法得知,不能进行转移,然后我就卡在这里了。注意到不管 <span
class="math inline">\(\text{mex}\)</span> 是什么数, 假设 <span
class="math inline">\(s_{i + 1} = 1\)</span>,那么 <span
class="math inline">\(a_{i + 1}\)</span> 一定在 <span
class="math inline">\(a_1 , a_{2} , \cdots, a_{i}\)</span>
中没出现过。那我们不妨设 <span class="math inline">\(f_{i, j}\)</span>
代表前 <span class="math inline">\(i\)</span> 个位置在满足题意的条件下有
<span class="math inline">\(j\)</span>
个不同的数的方案数,这样可以巧妙避免 <span
class="math inline">\(\text{mex}\)</span>
被记录到状态中导致无法转移的问题,更具体地说 <span
class="math inline">\(\text{mex}\)</span> 只会对这个 dp
的转移过程进行限制。若 <span class="math inline">\(s_{i + 1} =
1\)</span>,相当于<strong>能且只能</strong>填入 <span
class="math inline">\(\text{mex}\{a_1, a_2, \cdots,
a_{n}\}\)</span>,所以 <span class="math inline">\(j\)</span> 一定会加
<span class="math inline">\(1\)</span>,即进行转移 <span
class="math inline">\(f_{i, j} \rightarrow f_{i + 1, j + 1}\)</span>
;若 <span class="math inline">\(s_{i + 1} =
0\)</span>,如果填入之前已经填入的数,即进行转移 <span
class="math inline">\(j \times f_{i, j} \rightarrow f_{i + 1,
j}\)</span>,如果填入之前不存在的数,那么有 <span
class="math inline">\((m + 1) - j - 1\)</span> 种填数方式,减 <span
class="math inline">\(1\)</span> 是因为 <span
class="math inline">\(\text{mex}\{a_1, a_2, \cdots, a_{n}\}\)</span>
不能填,即进行转移 <span class="math inline">\((m - j) \times f_{i, j}
\rightarrow f_{i + 1, j + 1}\)</span>。最终答案 <span
class="math inline">\(\displaystyle{ans = \sum\limits_{i = 1}^{\min(n, m
+ 1)} f_{n, i}}\)</span>,时间复杂度为 <span
class="math inline">\(O(n^{2})\)</span>,可以通过。</p>
<h2 id="section-7">1.22</h2>
<p>vp 了 <a
href="https://codeforces.com/contest/1777/problem/D">Codeforces Round
845 Div.2</a>,赛时 <span class="math inline">\(4\)</span>
题,后面的题还没补,但是觉得 D 挺有意思的,遂记录一下。</p>
<p><strong>题目 <span class="math inline">\(13\)</span> :</strong><a
href="https://codeforces.com/contest/1777/problem/D">CF1777D - Score of
a Tree</a> <span
class="math inline">\(\textcolor{brown}{\bigstar}\)</span>
<strong>[贡献的拆分 | 树形结构]</strong></p>
<p><strong>思路:</strong>考虑把贡献拆开,计算每个结点 <span
class="math inline">\(x\)</span> 在 <span
class="math inline">\(t\)</span> 时刻对答案的贡献。注意到结点 <span
class="math inline">\(x\)</span> 在 <span
class="math inline">\(t\)</span> 时刻的值只会被 <span
class="math inline">\(x\)</span> 向下 <span
class="math inline">\(t\)</span> 层的子节点影响,假设 <span
class="math inline">\(x\)</span> 向下 <span
class="math inline">\(t\)</span> 层的子节点有 <span
class="math inline">\(cnt\)</span> 个,那么这 <span
class="math inline">\(cnt\)</span> 个结点的权值在 <span
class="math inline">\(t = 0\)</span> 时有奇数个 <span
class="math inline">\(1\)</span> 才能使得 <span
class="math inline">\(x\)</span> 结点在 <span
class="math inline">\(t\)</span> 时刻的权值为 <span
class="math inline">\(1\)</span>,所以初始时这 <span
class="math inline">\(cnt\)</span> 个结点的方案数为 <span
class="math inline">\(\binom{cnt}{1} + \binom{cnt}{3} + \binom{cnt}{5} +
\cdots = 2^{cnt - 1}\)</span>,因为其他结点初始的值对 <span
class="math inline">\(x\)</span> 在 <span
class="math inline">\(t\)</span> 时刻的权值没有影响,所以有 <span
class="math inline">\(2^{n - cnt}\)</span> 种方案。所以如果 <span
class="math inline">\(x\)</span> 向下 <span
class="math inline">\(t\)</span>
层具有子节点,不管具有多少个子节点,对答案的贡献都是 <span
class="math inline">\(2^{cnt - 1} \times 2^{n - cnt} = 2^{n -
1}\)</span>。所以只需要 dfs
求出每个节点向下最深的结点的深度,然后计算贡献即可。</p>
<h2 id="section-8">1.23</h2>
<p>学长给预备队出了一套模拟赛,听到学长讲了一个有意思的东西,就是三个整点没法组成一个等边三角形。因为边长
<span class="math inline">\(a\)</span> 的平方一定是整数,而 <span
class="math inline">\(\displaystyle{S =
\frac{\sqrt{3}}{4}a^{2}}\)</span>
一定是无理数,但是根据皮克定理,整点多边形的面积一定是有理数,所以一定不存在三个整点构成的等边三角形。</p>
<p>补了一下上场 ARC 的 D 题,一个很有意思的博弈论思维题。</p>
<p><strong>题目 <span class="math inline">\(\text{14}\)</span>
:</strong><a
href="https://atcoder.jp/contests/arc170/tasks/arc170_d">ARC170D -
Triangle Card Game</a> <span
class="math inline">\(\textcolor{blue}{\bigstar}\)</span>
<strong>[博弈论 | 思维题]</strong></p>
<p><strong>思路:</strong>考虑组成三角形的三边满足的限制,发现写成三个不等式非常繁琐,但可以简化一下写法。假设
<span class="math inline">\(a \ge b > 0\)</span>,则 <span
class="math inline">\(a, b, c\)</span> 构成三角形的充要条件是 <span
class="math inline">\(a - b < c < a + b\)</span>。发现只要确定了
<span class="math inline">\(a, b\)</span>,那么 <span
class="math inline">\(c\)</span> 必须落在区间 <span
class="math inline">\((a - b, a + b)\)</span> 上。假设 Alice 选了 <span
class="math inline">\(a_i\)</span>,Bob 选了 <span
class="math inline">\(b_j\)</span>,那么有两种情况:</p>
<ol type="1">
<li><p><span class="math inline">\(a_i \ge b_j\)</span></p>
<p>此时 Alice 下一次必须选区间 <span class="math inline">\((a_i - b_j,
a_i + b_j)\)</span> 上的数才能赢,所以 Bob 肯定希望 Alice
能选的可行区间半径尽量小,所以 Bob 一定会选 <span
class="math inline">\(b_{1}\)</span>(假设数组 <span
class="math inline">\(a, b\)</span>
都从小到大排过序了),这样我们只需要看有没有 <span
class="math inline">\(a_k\)</span> 满足 <span class="math inline">\(k
\neq i\)</span> 且 <span class="math inline">\(a_{k} \in (a_i - b_1, a_i
+ b_1)\)</span> 即可,实际上就是判断距离 <span
class="math inline">\(a_i\)</span> 最近的数的距离是否小于 <span
class="math inline">\(b_1\)</span>。</p></li>
<li><p><span class="math inline">\(a_i < b_j\)</span></p>
<p>此时 Alice 下一次必须选区间 <span class="math inline">\((b_j - a_i,
b_j + a_i)\)</span> 上的数才能赢。此时 <span
class="math inline">\(a_i\)</span> 为可选区间的半径,半径越大 Alice
肯定越容易赢。再结合 <span class="math inline">\(1\)</span>
中的分析,可以得出 Alice 的最优策略为:在保证 Bob 选择 <span
class="math inline">\(b_1\)</span> 时自己不会输的条件下,选择最大的
<span class="math inline">\(a_i\)</span>。</p></li>
</ol>
<p>由上,我们可以 <span class="math inline">\(O(n\log n)\)</span>
地解决此题,其中的 <span class="math inline">\(\log\)</span>
来自排序。</p>
<h2 id="section-9">1.24</h2>
<p>听 czy
学长讲了个奥数题思维题,准备出到预备队的比赛里,觉得很有意思,准备专门开一篇博客记录这种题和类似的
idea。</p>
<h2 id="section-10">1.25</h2>
<p>又 vp 了一场 <a href="https://codeforces.com/contest/1905">CF
div.2</a>,赛后补了 D 和 E 写一下简要题解,D
是一个均摊时间复杂度的妙妙题。</p>
<p><strong>题目 <span class="math inline">\(\text{15}\)</span>
:</strong><a
href="https://codeforces.com/contest/1905/problem/D">CF1905D - Cyclic
MEX</a> <span class="math inline">\(\textcolor{brown}{\bigstar}\)</span>
<strong>[时间复杂度均摊]</strong></p>
<p><strong>思路:</strong>先把 <span class="math inline">\(0\)</span>
移到最右边,考虑每次循环左移时每个位置 <span
class="math inline">\(\text{mex}\)</span> 的变化。容易得到 <span
class="math inline">\(0\)</span> 左边的所有位置的 <span
class="math inline">\(\text{mex}\)</span> 全都是 <span
class="math inline">\(0\)</span>,假设循环左移时最左边移到最右边的数是
<span class="math inline">\(x\)</span>,那么 <span
class="math inline">\(0\)</span> 右边所有位置的 <span
class="math inline">\(\text{mex}\)</span> 如果比 <span
class="math inline">\(x\)</span> 小则不会受到影响,如果比 <span
class="math inline">\(x\)</span> 大则会变成 <span
class="math inline">\(x\)</span>,最后一个位置的 <span
class="math inline">\(\text{mex}\)</span> 依然是 <span
class="math inline">\(n\)</span>。所以相当于维护一个单调非降的序列的和,每次操作把大于
<span class="math inline">\(x\)</span> 的后缀变成 <span
class="math inline">\(x\)</span>,并且在末尾添加上一个 <span
class="math inline">\(n\)</span>。我们可以把连续且相同的一些位置缩成一个块,这样每次暴力修改是
<span class="math inline">\(O(cnt)\)</span> 的,<span
class="math inline">\(cnt\)</span> 是大于 <span
class="math inline">\(x\)</span>
的块数。因为每个块只会被删除一次,每次修改最多添加 <span
class="math inline">\(2\)</span> 个新的块,所以总块数 <span
class="math inline">\(O(\sum cnt) = O(n)\)</span>,均摊每次操作是 <span
class="math inline">\(O(1)\)</span>,总时间复杂度是 <span
class="math inline">\(O(n)\)</span> 的。</p>
<p><strong>题目 <span class="math inline">\(\text{16}\)</span>
:</strong><a
href="https://codeforces.com/contest/1905/problem/E">CF1905E - One-X</a>
<span class="math inline">\(\textcolor{blue}{\bigstar}\)</span>
<strong>[贡献的拆分 | dp]</strong></p>
<p><strong>思路:</strong>注意到线段树每层最多只有<strong>两种</strong>不同的线段长度,而且根节点线段长度相同的线段树的结构是相同的。假设当前根节点线段长度是
<span class="math inline">\(len\)</span>,编号为 <span
class="math inline">\(id\)</span>,那么当前结点产生的贡献是 <span
class="math inline">\(id \cdot (2^{\lfloor\frac{len + 1}{2}\rfloor} -
1)\cdot (2^{\lfloor\frac{len}{2}\rfloor} -
1)\)</span>。所以直接递推出每一层的两种线段的个数与编号之和,直接计算贡献即可。加上快速幂,总时间复杂度是
<span class="math inline">\(O(\log^{2}(n))\)</span> 的。</p>
<h2 id="section-11">1.26</h2>
<p>晚上打了一场 <a href="https://codeforces.com/contest/1925">CF Round
921 div.2</a>,赛时 <span class="math inline">\(59\text{min}\)</span>
做了 <span class="math inline">\(4\)</span>
题终于上紫名了,总算是实现了高中退役前的梦想。</p>
<p>晚上随便打了点牛客周赛的题,就不写了。</p>
<p><strong>题目 <span class="math inline">\(\text{17}\)</span>
:</strong><a
href="https://codeforces.com/contest/1925/problem/E">CF1925E - Space
Harbour</a> <span
class="math inline">\(\textcolor{brown}{\bigstar}\textcolor{magenta}{\bigstar}\)</span>
<strong>[线段树]</strong></p>
<p><strong>思路:</strong>考虑在 <span
class="math inline">\(pos\)</span>
位置插入一个新的港口对其他位置的贡献。对于 <span
class="math inline">\(pos\)</span> 左边,插入前的总贡献是 <span
class="math inline">\(v_{pre} \times (nxt - x)\)</span>,插入后总贡献是
<span class="math inline">\(v_{pre} \times(pos - x)\)</span>,<span
class="math inline">\(\Delta = v_{pre}\times(pos - nxt)\)</span>。对于
<span class="math inline">\(pos\)</span> 右边,插入前的总贡献是 <span
class="math inline">\(v_{pre} \times (nxt - x)\)</span>,插入后的总贡献
<span class="math inline">\(v_{pos} \times (nxt - x)\)</span>,<span
class="math inline">\(\Delta = (v_{pos} - v_{pre}) \times(nxt - x) =
-(v_{pos} - v_{pre})x +(v_{pos} - v_{pre})nxt\)</span>。所以每个位置
<span class="math inline">\(x\)</span> 的贡献是 <span
class="math inline">\(kx + b\)</span> 的形式,操作只有对 <span
class="math inline">\(k\)</span> 和 <span
class="math inline">\(b\)</span> 的区间加,对 <span
class="math inline">\(kx + b\)</span> 的区间查询,可以用线段树维护。</p>
<h2 id="section-12">1.27</h2>
<p>补一下昨天的 CF div.2 的 F 题。</p>
<p><strong>题目 <span class="math inline">\(\text{18}\)</span>
:</strong> <a
href="https://codeforces.com/contest/1925/problem/F">CF1925F - Fractal
Origami</a> <span
class="math inline">\(\textcolor{blue}{\bigstar}\)</span>
<strong>[几何]</strong></p>
<p><strong>思路:</strong><a
href="https://tle-automat.top/2024/02/02/%E3%80%90%E9%A2%98%E8%A7%A3%E3%80%91CF1925F/#more">【题解】CF1925F</a></p>
<h2 id="section-13">1.28 ~ 1.30</h2>
<p>摸鱼 + 摆烂 + 给最后一场比赛搞题。</p>
<h2 id="section-14">1.31</h2>
<p>收拾东西,回家喽!</p>
]]></content>
<categories>
<category>杂题</category>
</categories>
<tags>
<tag>QwQ</tag>
</tags>
</entry>
<entry>
<title>【题解】洛谷P10572 - [JRKSJ R8] +1-1</title>
<url>/2024/07/03/%E3%80%90%E9%A2%98%E8%A7%A3%E3%80%91%E6%B4%9B%E8%B0%B7P10572%20%5BJRKSJ%20R8%5D%20+1-1/</url>
<content><![CDATA[<h2 id="解题思路">解题思路</h2>
<p>先考虑几个<strong>必要条件</strong>:</p>
<ul>
<li><span class="math inline">\(x\)</span> 结点是 <code>(</code> 且
<span class="math inline">\(y\)</span> 结点是 <code>)</code>。</li>
<li><span class="math inline">\(x\)</span> 到 <span
class="math inline">\(y\)</span> 至少有一条路径经过偶数个结点。</li>
</ul>
<p>在此之外,我们注意到如果路径的开头存在连续两个
<code>(</code>,那么可以在上面来回走来刷左括号;如果路径的结尾存在两个
<code>)</code>,那么可以在上面来回走来刷右括号。</p>
<p>那么一个初步的想法就是:</p>
<ul>
<li>如果 <span class="math inline">\(x\)</span>
可以直接沿着左右括号交替的路径走到 <span
class="math inline">\(y\)</span>,那就做完了。</li>
<li>否则,从 <span class="math inline">\(x\)</span>
沿着交替的左右括号一直走,走到某一个
<code>((</code>,然后开始刷足够多的左括号,然后原路返回 <span
class="math inline">\(x\)</span>,再从 <span
class="math inline">\(x\)</span> 沿着某条经过偶数个结点的路径走到 <span
class="math inline">\(y\)</span>,从 <span
class="math inline">\(y\)</span> 沿着交替的左右括号一直走,走到某一个
<code>))</code>,然后开始刷右括号,刷到与剩下的左括号平衡,然后返回
<span class="math inline">\(y\)</span> 即可。</li>
</ul>
<span id="more"></span>
<p>第一种情况正确性显然。</p>
<p>第二种情况,三段路径中每段路径经过的点数都是偶数,且前面刷了足够多的左括号让中间的段的每个右括号都能匹配,且最后能够刷右括号去抵消之前刷多了的左括号,所以也是正确的。</p>
<p>那么如果这两种情况都不满足,说明从 <span
class="math inline">\(x\)</span> 沿着左右交替的括号无法走到 <span
class="math inline">\(y\)</span> 也无法走到 <code>((</code>,只能走到
<code>))</code>,那这样显然不合法。</p>
<p>所以思路想完了,现在考虑如何实现。</p>
<ul>
<li><p><strong>第一步,我们要先判断 <span
class="math inline">\(x\)</span> 到 <span
class="math inline">\(y\)</span>
是否至少有一条路径经过偶数个结点。</strong></p>
<ol type="1">
<li><p>如果图是二分图,那么只需要判断 <span class="math inline">\(x,
y\)</span> 是否不在同一部。</p></li>
<li><p>如果图不是二分图,那么说明图中一定存在奇环,那么可以在这个奇环上绕一圈来控制奇偶性,这样任意两点
<span class="math inline">\(x, y\)</span>
之间一定有经过偶数个结点偶数的路径。</p></li>
</ol></li>
<li><p><strong>第二步,我们要判断 <span class="math inline">\(x\)</span>
是否能通过交替的左右括号走到 <span
class="math inline">\(y\)</span>。</strong></p>
<p>这个我们只需要保留原图中从 <code>(</code> 连向 <code>)</code>
的边,然后使用并查集判断 <span class="math inline">\(x, y\)</span>
是否在同一个连通块即可。</p></li>
<li><p><strong>第三步,我们要判断 <span class="math inline">\(x\)</span>
是否能通过交替的左右括号走到某一个 <code>((</code></strong>。</p>
<p>这个我们只需要在第二步的图中把 <code>((</code>
的两个括号所在的连通块打个标记即可。</p></li>
<li><p><strong>第四步,我们要判断 <span class="math inline">\(y\)</span>
是否能通过交替的左右括号走到某一个 <code>))</code></strong></p>
<p>这个跟第三步同理。</p></li>
</ul>
<p>注意这题并<strong>不保证图联通</strong>,还要额外判一下连通性,然后就完结撒花了。</p>
<h2 id="code">Code</h2>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><bits/stdc++.h></span></span></span><br><span class="line"></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="meta">#<span class="keyword">define</span> SZ(x) ((int)((x).size()))</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> lb(x) ((x) & (-(x)))</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> bp(x) __builtin_popcount(x)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> bpll(x) __builtin_popcountll(x)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> mkp make_pair</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> pb push_back</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> fi first</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> se second</span></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> <span class="type">unsigned</span> <span class="type">long</span> <span class="type">long</span> ull;</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">typedef</span> pair<ll, <span class="type">int</span>> pli;</span><br><span class="line"><span class="keyword">typedef</span> pair<ll, ll> pll;</span><br><span class="line"><span class="keyword">typedef</span> pair<<span class="type">double</span>, <span class="type">int</span>> pdi;</span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MAXN = <span class="number">5e5</span> + <span class="number">10</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">Dsu</span> {</span><br><span class="line"> vector<<span class="type">int</span>> fa;</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> n)</span> </span>{</span><br><span class="line"> fa.<span class="built_in">resize</span>(n + <span class="number">1</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"> fa[i] = i;</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">fifa</span><span class="params">(<span class="type">int</span> x)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (fa[x] == x) {</span><br><span class="line"> <span class="keyword">return</span> x;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> fa[x] = <span class="built_in">fifa</span>(fa[x]);</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> </span>{</span><br><span class="line"> x = <span class="built_in">fifa</span>(x);</span><br><span class="line"> y = <span class="built_in">fifa</span>(y);</span><br><span class="line"> <span class="keyword">if</span> (x != y) {</span><br><span class="line"> fa[x] = y;</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, q;</span><br><span class="line">string s;</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="function"><span class="type">void</span> <span class="title">solve</span><span class="params">()</span> </span>{</span><br><span class="line"> cin >> n >> m >> q >> s;</span><br><span class="line"> s = <span class="string">' '</span> + s;</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> u, v;</span><br><span class="line"> cin >> u >> v;</span><br><span class="line"> G[u].<span class="built_in">push_back</span>(v);</span><br><span class="line"> G[v].<span class="built_in">push_back</span>(u);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> cnt_id = <span class="number">0</span>;</span><br><span class="line"> <span class="function">vector <span class="title">cop_id</span><span class="params">(n + <span class="number">1</span>, <span class="number">0</span>)</span></span>;</span><br><span class="line"> <span class="keyword">auto</span> dfs_cop = [&](<span class="keyword">auto</span>&& self, <span class="type">int</span> u) -> <span class="type">void</span> {</span><br><span class="line"> cop_id[u] = cnt_id;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">auto</span> v : G[u]) {</span><br><span class="line"> <span class="keyword">if</span> (cop_id[v]) {</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">self</span>(self, 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">1</span>; i <= n; i++) {</span><br><span class="line"> <span class="keyword">if</span> (!cop_id[i]) {</span><br><span class="line"> cnt_id++;</span><br><span class="line"> <span class="built_in">dfs_cop</span>(dfs_cop, i);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function">vector <span class="title">is_erfen</span><span class="params">(n + <span class="number">1</span>, <span class="literal">true</span>)</span></span>;</span><br><span class="line"> <span class="function">vector <span class="title">clr</span><span class="params">(n + <span class="number">1</span>, <span class="number">-1</span>)</span></span>;</span><br><span class="line"> <span class="keyword">auto</span> dfs_clr = [&](<span class="keyword">auto</span>&& self, <span class="type">int</span> u, <span class="type">int</span> idx) -> <span class="type">void</span> {</span><br><span class="line"> <span class="keyword">if</span> (!is_erfen[idx]) {</span><br><span class="line"> <span class="keyword">return</span> ;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">auto</span> v : G[u]) {</span><br><span class="line"> <span class="keyword">if</span> (clr[v] == <span class="number">-1</span>) {</span><br><span class="line"> clr[v] = !clr[u];</span><br><span class="line"> <span class="built_in">self</span>(self, v, idx);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (clr[v] == clr[u]) {</span><br><span class="line"> is_erfen[idx] = <span class="literal">false</span>;</span><br><span class="line"> <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">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> (clr[i] == <span class="number">-1</span>) {</span><br><span class="line"> clr[i] = <span class="number">0</span>;</span><br><span class="line"> <span class="built_in">dfs_clr</span>(dfs_clr, i, cop_id[i]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> Dsu dsu;</span><br><span class="line"> dsu.<span class="built_in">init</span>(n);</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">for</span> (<span class="keyword">auto</span> v : G[u]) {</span><br><span class="line"> <span class="keyword">if</span> (s[u] != s[v]) {</span><br><span class="line"> dsu.<span class="built_in">merge</span>(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">vector <span class="title">flgl</span><span class="params">(n + <span class="number">1</span>, <span class="literal">false</span>)</span>, <span class="title">flgr</span><span class="params">(n + <span class="number">1</span>, <span class="literal">false</span>)</span></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">for</span> (<span class="keyword">auto</span> v : G[u]) {</span><br><span class="line"> <span class="keyword">if</span> (s[u] == <span class="string">'('</span> && s[v] == <span class="string">'('</span>) {</span><br><span class="line"> flgl[dsu.<span class="built_in">fifa</span>(u)] = <span class="literal">true</span>;</span><br><span class="line"> flgl[dsu.<span class="built_in">fifa</span>(v)] = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (s[u] == <span class="string">')'</span> && s[v] == <span class="string">')'</span>) {</span><br><span class="line"> flgr[dsu.<span class="built_in">fifa</span>(u)] = <span class="literal">true</span>;</span><br><span class="line"> flgr[dsu.<span class="built_in">fifa</span>(v)] = <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><br><span class="line"> string ans;</span><br><span class="line"> <span class="keyword">while</span> (q--) {</span><br><span class="line"> <span class="type">int</span> x, y;</span><br><span class="line"> cin >> x >> y;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (cop_id[x] != cop_id[y]) {</span><br><span class="line"> ans += <span class="string">'0'</span>;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="type">int</span> id = cop_id[x];</span><br><span class="line"> <span class="keyword">if</span> (is_erfen[id] && clr[x] == clr[y]) {</span><br><span class="line"> ans += <span class="string">'0'</span>;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (s[x] != <span class="string">'('</span> || s[y] != <span class="string">')'</span>) {</span><br><span class="line"> ans += <span class="string">'0'</span>;</span><br><span class="line"> <span class="keyword">continue</span>;</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">fifa</span>(x) == dsu.<span class="built_in">fifa</span>(y)) {</span><br><span class="line"> ans += <span class="string">'1'</span>;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (flgl[dsu.<span class="built_in">fifa</span>(x)] && flgr[dsu.<span class="built_in">fifa</span>(y)]) {</span><br><span class="line"> ans += <span class="string">'1'</span>;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> ans += <span class="string">'0'</span>;</span><br><span class="line"> }</span><br><span class="line"> cout << ans << <span class="string">'\n'</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"> ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line"> cin.<span class="built_in">tie</span>(<span class="number">0</span>), cout.<span class="built_in">tie</span>(<span class="number">0</span>);</span><br><span class="line"> <span class="type">int</span> T = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (T--) <span class="built_in">solve</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>
]]></content>
<categories>
<category>杂题选做</category>
</categories>
<tags>
<tag>图论</tag>
<tag>括号序列</tag>
</tags>
</entry>
<entry>
<title>ABC352G - Socks 3</title>
<url>/2024/05/07/%E3%80%90%E9%A2%98%E8%A7%A3%E3%80%91ABC352G/</url>
<content><![CDATA[<h2 id="题目链接">题目链接</h2>
<p><a
href="https://atcoder.jp/contests/abc352/tasks/abc352_g">https://atcoder.jp/contests/abc352/tasks/abc352_g</a></p>
<h2 id="题目大意">题目大意</h2>
<p>总共有 <span class="math inline">\(N\)</span> 种不同颜色的袜子,第
<span class="math inline">\(i\)</span> 种颜色的袜子有 <span
class="math inline">\(A_i\)</span>
只。现在高桥要按照以下规则决定早上穿哪一双袜子:</p>
<ul>
<li><p>从当前剩余的袜子中等概率随机且不放回地抽取一只袜子。</p></li>
<li><p>若抽出的袜子颜色与之前某次抽出的袜子颜色相同,则停止操作并穿这种颜色的袜子;</p>
<p>若抽出的袜子颜色与之前每一次抽出的颜色均不同,则进行下一次抽取操作。</p></li>
</ul>
<p>求高桥抽取袜子次数的期望值,对 <span
class="math inline">\(998244353\)</span> 取模。</p>
<h2 id="数据范围">数据范围</h2>
<ul>
<li><span class="math inline">\(1 \le N \le 3\times 10^{5}\)</span></li>
<li><span class="math inline">\(2 \le A_i \le 3000\)</span></li>
</ul>
<span id="more"></span>
<h2 id="解题思路">解题思路</h2>
<p>设 <span class="math inline">\(f_k\)</span> 代表抽了 <span
class="math inline">\(k\)</span>
次袜子之后还没有凑出来一对相同颜色袜子的概率,那 <span
class="math inline">\(f_k - f_{k + 1}\)</span> 就是第 <span
class="math inline">\(k + 1\)</span>
次抽袜子凑出来了一对相同颜色袜子的概率,设 <span
class="math inline">\(tot = \sum A_i\)</span>,那么期望次数就是 <span
class="math inline">\(\displaystyle{\sum_{k = 0}^{n}} (f_k - f_{k + 1})
\times (k + 1)\)</span>。接下来考虑怎么求出 <span
class="math inline">\(f\)</span>。</p>
因为每种袜子抽到不能超过 <span class="math inline">\(1\)</span>
次,考虑枚举抽到了 <span class="math inline">\(p_1, p_2, \cdots,
p_k\)</span> 这些种类的袜子,那么有 $$
<span class="math display">\[\begin{aligned}
f_k &= \sum\limits_{\{p_1, p_2, \cdots, p_k\} \subset \{1, 2,
\cdots, n\}} k! \cdot \frac{A_{p_1}}{tot} \cdot \frac{A_{p_2}}{tot - 1}
\cdots \frac{A_{p_k}}{tot - (k - 1)} \\
&= \frac{k!(tot - k)!}{tot!} \sum\limits_{\{p_1, p_2, \cdots, p_k\}
\subset \{1, 2, \cdots, n\}} A_{p_1} A_{p_2}\cdots A_{p_k}
\end{aligned}\]</span>
<p>$$ 令 <span class="math inline">\(g_k =
\displaystyle\sum\limits_{\{p_1, p_2, \cdots, p_k\} \subset \{1, 2,
\cdots, n\}} A_{p_1} A_{p_2}\cdots A_{p_k}\)</span>,注意到 <span
class="math inline">\(g_k\)</span> 的含义就是从 <span
class="math inline">\(n\)</span> 个里面选 <span
class="math inline">\(k\)</span> 个所有方案的乘积之和。</p>
<p>可以把序列分为左右两部分,两部分的 <span
class="math inline">\(g\)</span> 分别求出来,做一遍卷积就得到合起来的
<span class="math inline">\(g\)</span> 了,使用分治即可,时间复杂度
<span class="math inline">\(O(n\log^{2}n)\)</span>。</p>
<h2 id="参考代码">参考代码</h2>
<p><a
href="https://atcoder.jp/contests/abc352/submissions/53158065">https://atcoder.jp/contests/abc352/submissions/53158065</a></p>
]]></content>
<categories>
<category>AtCoder解题报告</category>
</categories>
<tags>
<tag>组合数学</tag>
<tag>概率与期望</tag>
<tag>多项式</tag>
</tags>
</entry>
<entry>
<title>【题解】AGC066A - Adjacent Difference</title>
<url>/2024/04/03/%E3%80%90%E9%A2%98%E8%A7%A3%E3%80%91AGC066A/</url>
<content><![CDATA[<h2 id="题目链接">题目链接</h2>
<p><a
href="https://atcoder.jp/contests/agc066/tasks/agc066_a">https://atcoder.jp/contests/agc066/tasks/agc066_a</a></p>
<h2 id="题目大意">题目大意</h2>
<p>给定一个 <span class="math inline">\(N \times N\)</span> 的方阵 <span
class="math inline">\(A_{i, j}\)</span> 和一个正整数 <span
class="math inline">\(d\)</span>。每次可以花费 <span
class="math inline">\(x\)</span> 的代价将矩阵的某一个位置加上 <span
class="math inline">\(x\)</span> 或减去 <span
class="math inline">\(x\)</span>。请构造一种方案使得方阵中所有相邻位置的差的绝对值大于等于
<span class="math inline">\(d\)</span>,且代价之和小于等于 <span
class="math inline">\(\frac{1}{2}N^{2}d\)</span>。</p>
<h2 id="数据范围">数据范围</h2>
<ul>
<li><span class="math inline">\(2\le N \le 500\)</span></li>
<li><span class="math inline">\(1\le d \le 1000\)</span></li>
<li><span class="math inline">\(-1000 \le A_{i, j} \le
1000\)</span></li>
</ul>
<span id="more"></span>
<h2 id="解题思路">解题思路</h2>
<p>先说结论:</p>
<ol type="1">
<li>将方阵黑白染色,然后将<strong>黑色</strong>的位置变为 <span
class="math inline">\(\bmod 2d = 0\)</span>
的最近的数,将<strong>白色</strong>的位置变为 <span
class="math inline">\(\bmod 2d = d\)</span> 的最近的数,假设代价此为
<span class="math inline">\(c_0\)</span>。</li>
<li>将方阵黑白染色,然后将<strong>白色</strong>的位置变为 <span
class="math inline">\(\bmod 2d = 0\)</span>
的最近的数,将<strong>黑色</strong>的位置变为 <span
class="math inline">\(\bmod 2d = d\)</span> 的最近的数,假设代价此为
<span class="math inline">\(c_1\)</span>。</li>
</ol>
<p>则上述两种情况中必有一种满足条件。</p>
<p>证明:</p>
<p>由于上述构造中黑白相邻位置的差的绝对值至少为 <span
class="math inline">\(d\)</span>,所以满足第一个条件。</p>
<p>考虑第二个条件。假设把一个位置上的数变为 <span
class="math inline">\(\bmod 2d = 0\)</span> 的最近数的代价为 <span
class="math inline">\(x\)</span>,变为 <span class="math inline">\(\bmod
2d = d\)</span> 的最近的数的代价为 <span
class="math inline">\(y\)</span>,那么一定有 <span
class="math inline">\(x + y = d\)</span>。这就意味着 <span
class="math inline">\(c_0 + c_1 = N ^ {2} d\)</span>,则 <span
class="math inline">\(c_0\)</span> 和 <span
class="math inline">\(c_1\)</span> 中必有一个小于等于 <span
class="math inline">\(\frac{1}{2}N^{2}d\)</span>。</p>
<h2 id="参考代码">参考代码</h2>
<p><a
href="https://atcoder.jp/contests/agc066/submissions/51989697">https://atcoder.jp/contests/agc066/submissions/51989697</a></p>
]]></content>
<categories>
<category>AtCoder解题报告</category>
</categories>
<tags>
<tag>人类の智慧</tag>
</tags>
</entry>
<entry>
<title>【题解】CF1942E - Farm Game</title>
<url>/2024/04/01/%E3%80%90%E9%A2%98%E8%A7%A3%E3%80%91CF1942E/</url>
<content><![CDATA[<h2 id="题目链接">题目链接</h2>
<p><a
href="https://codeforces.com/contest/1942/problem/E">https://codeforces.com/contest/1942/problem/E</a></p>
<h2 id="题目大意">题目大意</h2>
<p>小 N 和小 J 各有 <span class="math inline">\(n\)</span> 头奶牛,小 N
的奶牛位置为 <span class="math inline">\(a_1, a_2, \cdots,
a_n\)</span>,小 J 的奶牛位置为 <span class="math inline">\(b_1, b_2,
\cdots, b_n\)</span>。其中小 N 和小 J 的奶牛交替出现,且位置在 <span
class="math inline">\(1\)</span> 与 <span
class="math inline">\(l\)</span> 之间,即满足 <span
class="math inline">\(0 < a_1 < b_1 < a_2 < b_2 < \cdots
< a_n < b_n < l + 1\)</span> 或 <span class="math inline">\(0
< b_1 < a_1 < b_2 < a_2 < \cdots < b_n < a_n < l
+ 1\)</span>。</p>
<p>现在小 J 和小 N 轮流进行以下操作,小 J 先手:</p>
<ul>
<li>当前操作的人任意选中自己的 <span class="math inline">\(k(1 \le k \le
n)\)</span>
头奶牛,并且让这些奶牛一起向左或向右移动<strong>一格</strong>。移动后,位置不能与另外一个人的奶牛重合,也不能超出边界(即位置不能小于
<span class="math inline">\(1\)</span> 也不能大于 <span
class="math inline">\(n\)</span>)。</li>
<li>若无法进行上述操作,当前操作的人判负。</li>
</ul>
<p>问有多少种合法的序列组合 <span class="math inline">\((a,
b)\)</span>,使得小 J 必胜(两人均足够聪明)。</p>
<h2 id="数据范围">数据范围</h2>
<p>多组测试数据,保证</p>
<ul>
<li><span class="math inline">\(2 \le l \le 10^6 , \sum l \le
10^{6}\)</span></li>
<li><span class="math inline">\(1 \le n \le
\left\lfloor\frac{l}{2}\right\rfloor\)</span></li>
</ul>
<span id="more"></span>
<h2 id="解题思路">解题思路</h2>
<p>十分有意思的小清新博弈和组合数学题。</p>
<h3 id="step-1">Step 1</h3>
<p>这题要求我们对先手必胜态进行计数,要计数我们必须要先搞清楚先手必胜态长什么样子。</p>
<p>先考虑比较简单的情况,如果 <span class="math inline">\(n =
1\)</span>,此时发现如果小 J 的奶牛与小 N 的奶牛贴贴,那么小 J
必败;否则,小 J 和小 N 要尽量避免自己的奶牛被对方贴贴。</p>
<p>我们又发现,操作的人把自己的奶牛向使相对距离变远的方向移动是没有意义的,因为下一个操作的人模仿相同的动作总能把相对距离变回原来的状态。</p>
<p>所以 <span class="math inline">\(n = 1\)</span> 时小 J
是否必胜只与两头奶牛的相对距离的奇偶性有关。</p>
<h3 id="step-2">Step 2</h3>
<p>我们 <span class="math inline">\(n\)</span>