-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
835 lines (816 loc) · 102 KB
/
search.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
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
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>二分模板</title>
<url>/2020/09/19/%E4%BA%8C%E5%88%86%E6%A8%A1%E6%9D%BF/</url>
<content><![CDATA[<p>板子</p>
<a id="more"></a>
<p>目前二分模板有很多种,我觉得 $l<=r,l=mid+1,r=mid-1$ 是最好的,可以处理最大和最小的情况,判断无解也方便,但是需要记录ans。</p>
<h2 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现:"></a>代码实现:</h2><figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">int</span> l=<span class="number">1</span>,r=total,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="keyword">int</span> mid=(l+r)>><span class="number">1</span>;</span><br><span class="line"> <span class="keyword">int</span> could=check(mid);</span><br><span class="line"> <span class="keyword">if</span>(could>=need){ <span class="comment">//此种为求最大值,如果求最小值则反之</span></span><br><span class="line"> l=mid+<span class="number">1</span>;</span><br><span class="line"> ans=mid;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> r=mid<span class="number">-1</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> ans;</span><br></pre></td></tr></table></figure>
]]></content>
<tags>
<tag>笔记</tag>
<tag>二分</tag>
</tags>
</entry>
<entry>
<title>题解 Luogu P1280 [尼克的任务]</title>
<url>/2020/10/23/%E9%A2%98%E8%A7%A3-Luogu-P1280-%E5%B0%BC%E5%85%8B%E7%9A%84%E4%BB%BB%E5%8A%A1/</url>
<content><![CDATA[<p><a href="https://www.luogu.com.cn/problem/P1280">题目传送门</a></p>
<a id="more"></a>
<p>我们可以把每个时间看作一个点,每个任务就是一条边,那么最终我们只需要跑一遍DAG最短路,求出最短工作时间,最后用总时间减去最短工作时间求出答案。</p>
<p>解题步骤:</p>
<ol>
<li>对于一个任务,从<code>开始时间-1</code>的节点向<code>结束时间</code>连一条边,权值为<code>t</code>。</li>
<li>对于出度为0的点<code>i</code>,向<code>i+1</code>连一条边,权值为<code>0</code>。(即此时无任务可做)</li>
<li>跑一遍DAG最短路</li>
</ol>
<h2 id="代码:"><a href="#代码:" class="headerlink" title="代码:"></a>代码:</h2><figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cctype></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><algorithm></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><string></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cstring></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="keyword">int</span> <span class="title">read</span><span class="params">()</span></span>{<span class="comment">//快读</span></span><br><span class="line"> <span class="keyword">int</span> f=<span class="number">1</span>,num=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">char</span> rd=getchar();</span><br><span class="line"> <span class="keyword">while</span>(!<span class="built_in">isdigit</span>(rd)){</span><br><span class="line"> <span class="keyword">if</span>(rd==<span class="string">'-'</span>) f=<span class="number">-1</span>;</span><br><span class="line"> rd=getchar();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">while</span>(<span class="built_in">isdigit</span>(rd)){</span><br><span class="line"> num=num*<span class="number">10</span>+rd<span class="number">-48</span>;</span><br><span class="line"> rd=getchar();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> f*num;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> cnt,head[<span class="number">10009</span>],nex[<span class="number">20009</span>],to[<span class="number">20009</span>],w[<span class="number">20009</span>],dp[<span class="number">10009</span>];<span class="comment">//邻接表</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">add</span><span class="params">(<span class="keyword">int</span> x,<span class="keyword">int</span> y,<span class="keyword">int</span> c)</span></span>{</span><br><span class="line"> nex[++cnt]=head[x];</span><br><span class="line"> head[x]=cnt;</span><br><span class="line"> to[cnt]=y;</span><br><span class="line"> w[cnt]=c;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">dp_dfs</span><span class="params">(<span class="keyword">int</span> x)</span></span>{</span><br><span class="line"> <span class="keyword">if</span>(dp[x]!=<span class="number">0x3f3f3f3f</span>) <span class="keyword">return</span> dp[x];</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=head[x];i;i=nex[i]){</span><br><span class="line"> dp[x]=min(dp_dfs(to[i])+w[i],dp[x]);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> dp[x];</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">memset</span>(dp,<span class="number">0x3f</span>,<span class="keyword">sizeof</span>(dp));</span><br><span class="line"> <span class="keyword">int</span> n=read(),k=read();</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=k;i++){</span><br><span class="line"> <span class="keyword">int</span> x=read(),t=read();</span><br><span class="line"> add(x<span class="number">-1</span>,x+t<span class="number">-1</span>,t);</span><br><span class="line"> }</span><br><span class="line"> dp[n]=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i<n;i++) <span class="keyword">if</span>(!head[i]) add(i,i+<span class="number">1</span>,<span class="number">0</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>,n-dp_dfs(<span class="number">0</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>
<tags>
<tag>图论</tag>
<tag>DAG</tag>
<tag>题解</tag>
</tags>
</entry>
<entry>
<title>考前注意事项</title>
<url>/2020/11/04/%E8%80%83%E5%89%8D%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9/</url>
<content><![CDATA[<p>记得看看</p>
<a id="more"></a>
<ul>
<li>线段树记得开四倍数组</li>
<li>树链剖分加线段树时注意dfs序的映射</li>
<li>1左移31位以上记得先给1强制类型转换</li>
<li>INF为 <code>0x3f3f3f3f</code></li>
<li>分组背包记得循环顺序</li>
<li>不要在for里面对 <code>i</code> 之类的变量瞎搞</li>
<li><code>priority_queue</code> 是大根堆</li>
<li>最好不要用 <code>memset</code>,据说常数很大</li>
<li>RP++</li>
</ul>
]]></content>
<tags>
<tag>比赛</tag>
</tags>
</entry>
<entry>
<title>Dijkstra 单源最短路</title>
<url>/2020/11/05/Dijkstra-%E5%8D%95%E6%BA%90%E6%9C%80%E7%9F%AD%E8%B7%AF/</url>
<content><![CDATA[<p>一种高效率的单源最短路算法 <del>(SPFA的继任者)</del></p>
<a id="more"></a>
<p><a href="https://www.luogu.com.cn/problem/P4779">板子题传送门</a></p>
<h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><p>待填坑Orz</p>
<h2 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h2><figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><algorithm></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cstring></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cmath></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><string></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cctype></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><queue></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="keyword">int</span> <span class="title">read</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">int</span> f=<span class="number">1</span>,num=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">char</span> rd=getchar();</span><br><span class="line"> <span class="keyword">while</span>(!<span class="built_in">isdigit</span>(rd)){</span><br><span class="line"> <span class="keyword">if</span>(rd==<span class="string">'-'</span>) f=<span class="number">-1</span>;</span><br><span class="line"> rd=getchar();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">while</span>(<span class="built_in">isdigit</span>(rd)){</span><br><span class="line"> num=num*<span class="number">10</span>+rd<span class="number">-48</span>;</span><br><span class="line"> rd=getchar();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> f*num;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> cnt,head[<span class="number">100090</span>],nex[<span class="number">800900</span>],to[<span class="number">800900</span>];</span><br><span class="line"><span class="keyword">int</span> w[<span class="number">800900</span>],dis[<span class="number">100090</span>];<span class="comment">//看好数据范围,血的教训</span></span><br><span class="line"><span class="keyword">bool</span> vis[<span class="number">100090</span>];</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">add</span><span class="params">(<span class="keyword">int</span> x,<span class="keyword">int</span> y,<span class="keyword">int</span> c)</span></span>{</span><br><span class="line"> nex[++cnt]=head[x];</span><br><span class="line"> head[x]=cnt;</span><br><span class="line"> to[cnt]=y;</span><br><span class="line"> w[cnt]=c;</span><br><span class="line">}</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">node</span>{</span></span><br><span class="line"> <span class="keyword">int</span> num,val;</span><br><span class="line"> <span class="keyword">bool</span> <span class="keyword">operator</span> < (<span class="keyword">const</span> node &b) <span class="keyword">const</span>{<span class="comment">//重载运算符</span></span><br><span class="line"> <span class="keyword">return</span> val>b.val;</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"><span class="function">node <span class="title">make_node</span><span class="params">(<span class="keyword">int</span> x,<span class="keyword">int</span> y)</span></span>{</span><br><span class="line"> node a;</span><br><span class="line"> a.num=x;</span><br><span class="line"> a.val=y;</span><br><span class="line"> <span class="keyword">return</span> a;</span><br><span class="line">}</span><br><span class="line"><span class="built_in">priority_queue</span> <node> q;<span class="comment">//优先队列是大根堆</span></span><br><span class="line"><span class="keyword">int</span> n,m;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">solve</span><span class="params">(<span class="keyword">int</span> from)</span></span>{</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=n;i++) dis[i]=<span class="number">2147483647</span>;</span><br><span class="line"> q.push(make_node(from,<span class="number">0</span>));</span><br><span class="line"> dis[from]=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span>(!q.empty()){</span><br><span class="line"> <span class="keyword">int</span> u=q.top().num;</span><br><span class="line"> q.pop();</span><br><span class="line"> <span class="keyword">if</span>(vis[u]) <span class="keyword">continue</span>;</span><br><span class="line"> vis[u]=<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=head[u];i;i=nex[i]){</span><br><span class="line"> <span class="keyword">if</span>(dis[to[i]]>dis[u]+w[i]){</span><br><span class="line"> dis[to[i]]=dis[u]+w[i];</span><br><span class="line"> q.push(make_node(to[i],dis[to[i]]));</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="keyword">int</span> i=<span class="number">1</span>;i<=n;i++) <span class="built_in">printf</span>(<span class="string">"%d "</span>,dis[i]);</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> n=read(),m=read();<span class="keyword">int</span> u=read();</span><br><span class="line"> <span class="keyword">int</span> x,y,c;</span><br><span class="line"> <span class="keyword">while</span>(m--){</span><br><span class="line"> x=read(),y=read(),c=read();</span><br><span class="line"> add(x,y,c);</span><br><span class="line"> }</span><br><span class="line"> solve(u);</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>
<tags>
<tag>笔记</tag>
<tag>图论</tag>
</tags>
</entry>
<entry>
<title>CSP-S 2020 游记</title>
<url>/2020/11/06/CSP-S-2020-%E6%B8%B8%E8%AE%B0/</url>
<content><![CDATA[<p><del>T1出题人好家伙</del></p>
<a id="more"></a>
<h2 id="DAY-0"><a href="#DAY-0" class="headerlink" title="DAY 0"></a>DAY 0</h2><p>早上上了三节文化课,中间去体检了一下 <del>(视力不降反升的我真的是OIer吗)</del> 。学校包的车有一说一,是有点朴素,坐着感觉有点挤。</p>
<p>花了大约2小时到了泉州,先去宾馆安顿,房间暗无天日(悲)。然后休息了一会就去试机子,试的那台机子,屏幕跟炸了一样,各种花屏。然后更令我爆炸的是,去年我会写的题目,今年我不会了???心态有点裂开……</p>
<p>晚上去吃了“醉得意”,感觉菜挺好吃的,吃得挺饱,后面去麦当劳的时候,吃不下了 <del>(感觉错失一个亿)</del> 。教练买了一大堆东西,整得一手好活。</p>
<p>吃完回到宾馆,稍微写了一道Tarjan板子,然后就开始颓废,玩Minecraft,根本不想写题。</p>
<p>总而言之,今天来泉州真的不像是来比赛的,而是来旅游的,现在心态调整得差不多了,准备睡觉。祝明天RP++!</p>
<h2 id="DAY-1"><a href="#DAY-1" class="headerlink" title="DAY 1"></a>DAY 1</h2><p>早上睡到八九点,颓了一早上,没啥好说的,中午去考场那边的食堂吃了午饭,一般般,然后回宾馆睡了个觉。</p>
<p>下午开始考试,看到T1,woc?大模拟,给我人整傻了,想起来中午我毒奶了一波:“T1大模拟” “T1写不出”,结果完蛋,真的写不出来,不管它,先去开T2。T2小清新,稍微推了一下式子,秒了。</p>
<p>后面觉得T1非常可做,然后返回去搞T1。结果最后公历那部分爆炸了,前前后后整了快三个小时,后面幡然悔悟搞T4,可是只剩20min,只来得及骗20分。</p>
<p>最后出考场,跟人讨论了一下,忘记讨论 <code>k=64,n=0</code> 的情况,完蛋……</p>
<p>自我估分:30+90+0+20 = 140</p>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>这次CSP应该来说考得非常不理想,反映出了码力的不足,之前遇见要求码力大的题一般都不想写,结果导致现在T1挂掉,同时取舍的能力也有待提高,如果T1果断一点放弃,留个1小时,T4也是有可能写出来的。</p>
]]></content>
<tags>
<tag>比赛</tag>
</tags>
</entry>
<entry>
<title>Tarjan 缩点</title>
<url>/2020/11/06/Tarjan-%E7%BC%A9%E7%82%B9/</url>
<content><![CDATA[<p>可在 $O(n)$ 的时间复杂度内完成一个图的缩点</p>
<a id="more"></a>
<p><a href="https://www.luogu.com.cn/problem/P3387">板子题</a></p>
<h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><p>待填坑Orz</p>
<h2 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h2><figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cctype></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><algorithm></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><string></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cstring></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="keyword">int</span> <span class="title">read</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">int</span> f=<span class="number">1</span>,num=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">char</span> rd=getchar();</span><br><span class="line"> <span class="keyword">while</span>(!<span class="built_in">isdigit</span>(rd)){</span><br><span class="line"> <span class="keyword">if</span>(rd==<span class="string">'-'</span>) f=<span class="number">-1</span>;</span><br><span class="line"> rd=getchar();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">while</span>(<span class="built_in">isdigit</span>(rd)){</span><br><span class="line"> num=num*<span class="number">10</span>+rd<span class="number">-48</span>;</span><br><span class="line"> rd=getchar();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> f*num;</span><br><span class="line">}</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> MAXN 10090</span></span><br><span class="line"><span class="keyword">int</span> cnt,head[MAXN],nex[MAXN*<span class="number">10</span>],to[MAXN*<span class="number">10</span>];</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">add</span><span class="params">(<span class="keyword">int</span> x,<span class="keyword">int</span> y)</span></span>{</span><br><span class="line"> nex[++cnt]=head[x];</span><br><span class="line"> head[x]=cnt;</span><br><span class="line"> to[cnt]=y;</span><br><span class="line">}</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Stack</span>{</span></span><br><span class="line"> <span class="keyword">int</span> st[MAXN],size;</span><br><span class="line"> <span class="function"><span class="keyword">bool</span> <span class="title">empty</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> size?<span class="number">0</span>:<span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">push</span><span class="params">(<span class="keyword">int</span> x)</span></span>{</span><br><span class="line"> st[++size]=x;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">pop</span><span class="params">()</span></span>{</span><br><span class="line"> size--;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">top</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> st[size];</span><br><span class="line"> }</span><br><span class="line">}zhan;</span><br><span class="line"><span class="keyword">int</span> n,m;<span class="comment">//scc为染色后的编号</span></span><br><span class="line"><span class="keyword">int</span> dfn[MAXN],dfncnt,low[MAXN],scc[MAXN],ccnt;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Tarjan</span><span class="params">(<span class="keyword">int</span> x)</span></span>{</span><br><span class="line"> dfn[x]=++dfncnt;</span><br><span class="line"> low[x]=dfn[x];</span><br><span class="line"> zhan.push(x);</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=head[x];i;i=nex[i]){</span><br><span class="line"> <span class="keyword">if</span>(dfn[to[i]]&&(!scc[to[i]])){<span class="comment">//判断是否为后向边</span></span><br><span class="line"> low[x]=min(low[x],low[to[i]]);</span><br><span class="line"> }<span class="comment">//谨防手贱写错x和i</span></span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(!dfn[to[i]]){ <span class="comment">//判断是否为树枝边</span></span><br><span class="line"> Tarjan(to[i]);</span><br><span class="line"> low[x]=min(low[x],low[to[i]]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(low[x]==dfn[x]){</span><br><span class="line"> <span class="keyword">int</span> y;</span><br><span class="line"> ccnt++;</span><br><span class="line"> <span class="keyword">do</span>{</span><br><span class="line"> y=zhan.top();</span><br><span class="line"> zhan.pop();</span><br><span class="line"> scc[y]=ccnt;</span><br><span class="line"> }<span class="keyword">while</span>(x!=y);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">edge</span>{</span></span><br><span class="line"> <span class="keyword">int</span> x,y;</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">rd</span><span class="params">()</span></span>{</span><br><span class="line"> x=read(),y=read();</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">bool</span> <span class="title">pan</span><span class="params">()</span></span>{<span class="comment">//记得判断两边的scc不同</span></span><br><span class="line"> <span class="keyword">return</span> scc[x]!=scc[y];</span><br><span class="line"> }</span><br><span class="line">}e[MAXN*<span class="number">10</span>];</span><br><span class="line"><span class="keyword">int</span> dat[MAXN],news[MAXN];</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">rebuild</span><span class="params">()</span></span>{</span><br><span class="line"> cnt=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=n;i++) head[i]=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=m;i++) nex[i]=to[i]=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=m;i++) <span class="keyword">if</span>(e[i].pan()) add(scc[e[i].x],scc[e[i].y]); <span class="comment">//注意x与scc[x]之间的转换</span></span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=n;i++) news[scc[i]]+=dat[i];</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> dp[MAXN],ans;</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">dp_dfs</span><span class="params">(<span class="keyword">int</span> x)</span></span>{</span><br><span class="line"> <span class="keyword">if</span>(dp[x]) <span class="keyword">return</span> dp[x];</span><br><span class="line"> dp[x]=news[x];</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=head[x];i;i=nex[i]){</span><br><span class="line"> dp[x]=max(dp_dfs(to[i])+news[x],dp[x]);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> dp[x];</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> n=read(),m=read();</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=n;i++) dat[i]=read();</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=m;i++) e[i].rd();</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=m;i++) add(e[i].x,e[i].y);</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=n;i++) <span class="keyword">if</span>(!scc[i]) Tarjan(i);</span><br><span class="line"> rebuild();</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=n;i++) ans=max(ans,dp_dfs(scc[i]));</span><br><span class="line"> <span class="built_in">cout</span><<ans<<<span class="built_in">endl</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>
<tags>
<tag>笔记</tag>
<tag>图论</tag>
</tags>
</entry>
<entry>
<title>题解 Luogu P5020 [货币系统]</title>
<url>/2020/12/01/%E9%A2%98%E8%A7%A3-Luogu-P5020-%E8%B4%A7%E5%B8%81%E7%B3%BB%E7%BB%9F/</url>
<content><![CDATA[<p><a href="https://www.luogu.com.cn/problem/P5020">题目传送门</a></p>
<a id="more"></a>
<p>对于一个货币系统,一种货币能被取代当且仅当<strong>能被另外几种货币表示</strong>。举个例子,比如13元能被3元和5元表示,所以我们可以认为13元能被取代。</p>
<p>考虑记录每种面值能否被表示,记录一个 <code>book</code> 数组,然后我们就会惊讶地发现这就是一个完全背包。考虑枚举货币的顺序,容易想到一种货币只有可能被比它面值小的几种货币匹配,所以我们先排序一遍再进行DP。</p>
<h2 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h2><figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><algorithm></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cstring></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cmath></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><string></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cctype></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><queue></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="keyword">int</span> <span class="title">read</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">int</span> f=<span class="number">1</span>,num=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">char</span> rd=getchar();</span><br><span class="line"> <span class="keyword">while</span>(!<span class="built_in">isdigit</span>(rd)){</span><br><span class="line"> <span class="keyword">if</span>(rd==<span class="string">'-'</span>) f=<span class="number">-1</span>;</span><br><span class="line"> rd=getchar();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">while</span>(<span class="built_in">isdigit</span>(rd)){</span><br><span class="line"> num=num*<span class="number">10</span>+rd<span class="number">-48</span>;</span><br><span class="line"> rd=getchar();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> f*num;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> a[<span class="number">120</span>];</span><br><span class="line"><span class="keyword">bool</span> book[<span class="number">25004</span>];<span class="comment">//记录能否取到</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">solve</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">int</span> n=read(),maxn=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">int</span> m=n;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=n;i++) maxn=max(maxn,a[i]=read());</span><br><span class="line"> sort(a+<span class="number">1</span>,a+<span class="number">1</span>+n);</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=maxn;i++) book[i]=<span class="number">0</span>;</span><br><span class="line"> book[<span class="number">0</span>]=<span class="literal">true</span>;<span class="comment">//多测不清空,亲人两行泪</span></span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=n;i++){</span><br><span class="line"> <span class="keyword">if</span>(book[a[i]]){<span class="comment">//能被表示出来就从总数中减去1</span></span><br><span class="line"> m--;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> j=a[i];j<=maxn;j++) book[j]|=book[j-a[i]];</span><br><span class="line"> <span class="comment">//转移状态</span></span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>,m);</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> T=read();</span><br><span class="line"> <span class="keyword">while</span>(T--) solve();</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>
<tags>
<tag>题解</tag>
<tag>NOIP</tag>
<tag>DP</tag>
<tag>背包</tag>
</tags>
</entry>
<entry>
<title>NOIP2020 游记</title>
<url>/2020/12/05/NOIP2020-%E6%B8%B8%E8%AE%B0/</url>
<content><![CDATA[<p><del>打NOIP</del></p>
<p><del>去博物馆</del></p>
<p>跑马拉松</p>
<a id="more"></a>
<h2 id="DAY-0"><a href="#DAY-0" class="headerlink" title="DAY 0"></a>DAY 0</h2><p>本来说要去教室交个作业 <del>(炫耀)</del> ,但是床太舒服了,一觉醒来大家已经在做早操了,我们也要出发了……连早餐都来不及吃,裂开。</p>
<p>上路之后发现就是个NOIP2018复刻,公交,快艇,BRT一气呵成,一看就是经典路线。到了火车站,本来说要吃周麻婆,结果时间不大够,去吃了八婆婆。因为我不大喜欢吃豆花,所以点了烧仙草和煎饺,所幸逃过一劫,据同校OIer之言,这个豆花粉丝<strong>非常阴间</strong>。</p>
<p>在车上,没啥好说的,就颓废。</p>
<p>在酒店放了个行李之后去试了个机,4道题,不到20min秒了(好像都做过)。晚餐去吃了周麻婆,还行。</p>
<p>回到酒店,才发现我的房间是真的阳间,<del>我爱汉庭</del>。各种智能控制家具,说来可笑,我研究全智能马桶如何冲水研究了快5分钟……晚上别人出去大采购,我不想出去,结果错失了一个亿……</p>
<p><img src="https://s3.ax1x.com/2020/12/05/DOaHgK.jpg" alt="梦幻联动"></p>
<h2 id="DAY-1"><a href="#DAY-1" class="headerlink" title="DAY 1"></a>DAY 1</h2><p>早上吃了一波汉庭的阳间早餐,信心满满去比赛。</p>
<p>开局第一题:好家伙,DAG,反向记忆化搜索一下,秒了……吗?结果大数据莫名崩溃,调了快50min没调出来,裂开。</p>
<p>去看T2,面向数据编程,盲猜O(n),想了一会没思路,开始瞎搞打表找规律,事实证明我是邪教。没弄出来,返回去搞T1,发现是一个函数调用出了一个小锅,调了一下,大样例过了,不管了。</p>
<p>接下来就是各种骗分暴力,忽然发现,我现在不会骗分和暴力了,CSP2020和NOIP2020都没骗到分,回去好好学习骗分技巧。</p>
<p>考完试,心态有点裂开,去吃了个饭,然后买了个奶茶喝,去了省博物馆。挺好看的,买了一张十块钱的明信片,物超所值。参观完之后发现好像赶不上火车了,结果就是一个负重长跑……</p>
<p>万幸赶上了火车,在车上测了一波民间数据,结果总分90pts,总之就是非常裂开,非常迷茫,也许要退役了。</p>
]]></content>
<tags>
<tag>比赛</tag>
</tags>
</entry>
<entry>
<title>FOI2021 Summer DAY 1</title>
<url>/2021/07/11/FOI2021-Summer-DAY-1/</url>
<content><![CDATA[<h2 id="数据结构"><a href="#数据结构" class="headerlink" title="数据结构"></a>数据结构</h2><a id="more"></a>
<h3 id="队列"><a href="#队列" class="headerlink" title="队列"></a>队列</h3><h3 id="栈"><a href="#栈" class="headerlink" title="栈"></a>栈</h3><h3 id="倍增"><a href="#倍增" class="headerlink" title="倍增"></a>倍增</h3><p>预处理 $2^i$ 的信息。</p>
<p>作为思想,藏数据结构中发挥着重要的作用。如树状数组,线段树,RMQ。</p>
<h3 id="线段树"><a href="#线段树" class="headerlink" title="线段树"></a>线段树</h3><p>倍增思想,递归思想。<strong>开四倍空间!</strong></p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">通过提升简单操作的复杂度,降低困难操作的复杂度。</span><br><span class="line"> ————lk</span><br></pre></td></tr></table></figure>
<ul>
<li><p>模板题 <del>(水时长)</del></p>
</li>
<li><p>又一道模板题:引出 <code>lazy_tag</code> <del>(改了但没完全改)</del></p>
</li>
<li><p>又又一道模板题:要求支持区间加,区间乘,区间求和。直接维护两个 <code>lazy_tag</code> 即可。</p>
</li>
<li><p>略微不是很水的模板题,要求支持区间加,区间求和,区间求平方和。利用 $(a+b)^2=a^2+2ab+b^2$ 将加的 <code>lazy_tag</code> 巧妙地转化为区间的平方和的变化量。可以以此类推到 $n$ 次方。</p>
</li>
</ul>
<h3 id="权值线段树"><a href="#权值线段树" class="headerlink" title="权值线段树"></a>权值线段树</h3><ul>
<li><p>经典板子题:要求支持单点修改,查询第 $k$ 大的数。对权值建线段树后,查询时二分。</p>
</li>
<li><p><strong>动态开点</strong>:题目同上,不过值域变成 $[1,10^9]$ 。<del>指针党狂喜</del></p>
</li>
<li><p><strong>主席树</strong>:可持久化线段树,支持查询历史版本。</p>
</li>
</ul>
<h3 id="树状数组"><a href="#树状数组" class="headerlink" title="树状数组"></a>树状数组</h3><p>定义:对于数组中的 $x$ 号位置,若其二进制末尾有 $i$ 个 $0$ ,则其在第 $i$ 级,代表了一个长度为 $2^i$ 的区间的和。</p>
<p>例子:对于标号为 $12$ 的位置,其二进制表示为 $1100$ ,则其表示 $1001$ ~ $1100$ 位置的和。</p>
<p><del>可以靠背</del></p>
<ul>
<li>经典板子题:单点修改,区间求和。</li>
</ul>
<h3 id="RMQ"><a href="#RMQ" class="headerlink" title="RMQ"></a>RMQ</h3><ul>
<li><p>ST表:$O(1)$ 查询区间最大最小值。</p>
</li>
<li><p>RMQ求区间最值所在的位置:预处理ST表示,同时维护一个最值所在的下表即可。</p>
</li>
<li><p>RMQ求LCA:在欧拉序上,点 $u$ 和点 $v$ 中间深度最小的点就是它们的LCA。</p>
<p> 前置知识:dfs序(dfs遍历节点访问先后顺序),欧拉序(dfs遍历节点访问顺序)。</p>
</li>
</ul>
]]></content>
<tags>
<tag>FOI2021</tag>
</tags>
</entry>
<entry>
<title>FOI2021 Summer DAY 2</title>
<url>/2021/07/12/FOI2021-Summer-DAY-2/</url>
<content><![CDATA[<h2 id="字符串"><a href="#字符串" class="headerlink" title="字符串"></a>字符串</h2><a id="more"></a>
<h3 id="hash"><a href="#hash" class="headerlink" title="hash"></a>hash</h3><h4 id="前置知识:费马小定理"><a href="#前置知识:费马小定理" class="headerlink" title="前置知识:费马小定理"></a>前置知识:费马小定理</h4><p>$x^{p-1} \equiv 1 \pmod{p} ,p为质数$</p>
<p>hash是一种将字符串转化为数字的对应关系,用于加快字符串比较的速度。(不是一一对应的,所以可能有hash冲突)</p>
<ul>
<li>常见的hash方法: $f(s)=\sum s_i \times base^i \mod p$,p是一个质数,如 $998244353$,$10^9+7$ 。</li>
<li>求子串的hash值:$\frac{f(r)-f(l-1)}{base^{l-1}}$ 。</li>
</ul>
<h4 id="例题-1"><a href="#例题-1" class="headerlink" title="例题 1"></a>例题 1</h4><ul>
<li>简单习题:给定有小写字母构成的字符串 $S$ , $T$ ,问 $T$ 在 $S$ 中出现了多少次。</li>
</ul>
<h4 id="例题-2"><a href="#例题-2" class="headerlink" title="例题 2"></a>例题 2</h4><ul>
<li>又一道简单题:给定一个字符串 $S$ ,请你求出其中有多少个不同的长度为 $m$ 的字串。</li>
</ul>
<h4 id="例题-3"><a href="#例题-3" class="headerlink" title="例题 3"></a>例题 3</h4><ul>
<li><p>给定一个字符串 $S$ ,请你求出其中最长的回文串。</p>
<p> 正反hash后,枚举中心点,二分求最长回文串。时间复杂度为 $O(n \log n)$ 。</p>
</li>
</ul>
<h4 id="例题-4"><a href="#例题-4" class="headerlink" title="例题 4"></a><a href="https://www.luogu.com.cn/problem/P3538">例题 4</a></h4><ul>
<li><p>给定一个字符串 $S$ ,以及 $q$ 个询问查询子区间 $[l,r]$ 的最小循环节。</p>
<p>我们发现,一个字符串的循环节长度一定是它的长度的约数。所以我们可以将它优化到 $\sqrt{n}$ 的级别。在check长度为 $m$ 的时候,我们只需比较 $l$ ~ $r-m$ 和 $l+m$ ~ $r$ 的hash值是否相等。(待补推导过程)</p>
</li>
</ul>
<h3 id="Trie"><a href="#Trie" class="headerlink" title="Trie"></a>Trie</h3><p><del>好理解的数据结构</del></p>
<h4 id="例题-1-1"><a href="#例题-1-1" class="headerlink" title="例题 1"></a>例题 1</h4><ul>
<li>给定 $n$ 篇文章和 $m$ 个单词,求每个单词都在哪些文章出现过。</li>
</ul>
<h4 id="例题-2-1"><a href="#例题-2-1" class="headerlink" title="例题 2"></a>例题 2</h4><ul>
<li>给定 $n$ 个字符串 $s_i$ ,询问对于那些字符串,可以通过重排字母表顺序的方式使其字典序最小。$\sum s_i \leq 3 \times 10^5$</li>
</ul>
<p>在Trie树中插入所有字符串,然后每个字符串在树上跑一遍,对于每个字符大小关系,可以在一张图上连边,最后判环有无矛盾即可。</p>
<h4 id="例题-3-Reverse"><a href="#例题-3-Reverse" class="headerlink" title="例题 3 Reverse"></a>例题 3 Reverse</h4><ul>
<li><p>给定 $n$ 个数 $a_i$ ,你需要完成一下两种操作共 $q$ 次:</p>
<ol>
<li>给定 $k$ ,对于所有比 $k$ 大的数,做“Selia翻转”,Selia翻转是指将 $k$ 与被翻转的数写成二进制形式,找到他们最高的不同的位,翻转低于该位的所有二进制位;</li>
<li>询问 $[l,r]$ 内的数有几个。</li>
</ol>
<p>$n,q \leq 10^5,a_i \leq 10^9$</p>
</li>
</ul>
<p>考虑对所有数转化成二进制然后建01Trie,当我们翻转是,就按照大小关系,遍历到与 $k$ 不同的节点时,利用 <code>lazy_tag</code> ,打上标记,之后访问到这个节点再 <code>push_down</code> 。查询简单易懂,维护个 <code>size</code> 即可。</p>
<h3 id="KMP"><a href="#KMP" class="headerlink" title="KMP"></a>KMP</h3><h4 id="引入问题"><a href="#引入问题" class="headerlink" title="引入问题"></a>引入问题</h4><ul>
<li>(经典再放送)给定有小写字母构成的字符串 $S$ , $T$ ,问 $T$ 在 $S$ 中出现了多少次。</li>
</ul>
<h4 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h4><ul>
<li><strong>nex数组</strong>: $T$ 串的最长公共前后缀。</li>
<li><strong>如何求nex数组</strong>:跟自己做匹配。</li>
</ul>
<h4 id="例题-1-2"><a href="#例题-1-2" class="headerlink" title="例题 1"></a>例题 1</h4><ul>
<li>给定一个字符串 $S$ ,求多少种方案使得将字符串切成两部分,交换顺序之后与原串相同。</li>
</ul>
<p>将操作转化位复制一次原串于末尾,求其中原串个数,答案为 <code>原串个数-2</code> 。</p>
<h4 id="例题-2-2"><a href="#例题-2-2" class="headerlink" title="例题 2"></a>例题 2</h4><ul>
<li>给定字符串 $S$ ,你可以在 $S$ 末尾加上任意字符串 $T$ ,求 $S+T$ 的最小循环节。</li>
</ul>
<p>答案为 $n-nex_n$。(证明待补)</p>
<h3 id="AC自动机"><a href="#AC自动机" class="headerlink" title="AC自动机"></a>AC自动机</h3><h4 id="引入问题:"><a href="#引入问题:" class="headerlink" title="引入问题:"></a>引入问题:</h4><ul>
<li>给定一个匹配串 $S$ 和 $n$ 个被匹配串 $T_i$ ,求有多少串 $T_i$ 是 $S$ 的子串。</li>
</ul>
<h4 id="实现-1"><a href="#实现-1" class="headerlink" title="实现"></a>实现</h4><p><del>(要有一定的<strong>树理</strong>知识)</del></p>
<ol>
<li>首先对这 $n$ 个串建一个Trie树。</li>
<li>然后我们为每个节点建一类似于KMP的nex数组的fail</li>
</ol>
<h4 id="例题-1-文本生成器"><a href="#例题-1-文本生成器" class="headerlink" title="例题 1 文本生成器"></a><a href="https://www.luogu.com.cn/problem/P4052">例题 1 文本生成器</a></h4><ul>
<li>给定 $n$ 个字符串 $s_i$ ,求有多少长度为 $m$ 的字符串 $t$ ,满足 $t$ 中不存在任何一个子串 $s_i$ 。 $n,m,|s_i| \leq 100$</li>
</ul>
<h4 id="例题-2-3"><a href="#例题-2-3" class="headerlink" title="例题 2"></a>例题 2</h4><p>(待补)</p>
<h3 id="Manacher-马拉车"><a href="#Manacher-马拉车" class="headerlink" title="Manacher 马拉车"></a>Manacher <del>马拉车</del></h3><h4 id="引入问题-1"><a href="#引入问题-1" class="headerlink" title="引入问题"></a>引入问题</h4><ul>
<li>给定一个字符串,请你求出其中最长的回文串。</li>
</ul>
<p>对于偶数长度,只需要在两个相邻的字符间插入一个空字符即可。</p>
<h4 id="实现-2"><a href="#实现-2" class="headerlink" title="实现"></a>实现</h4><h4 id="例题-1-最长双回文串"><a href="#例题-1-最长双回文串" class="headerlink" title="例题 1 最长双回文串"></a>例题 1 最长双回文串</h4><ul>
<li>定义双回文串为两个回文串依次拼接而成的串,求 $s$ 的最长双回文串。</li>
</ul>
]]></content>
<tags>
<tag>FOI2021</tag>
</tags>
</entry>
<entry>
<title>FOI2021 Summer DAY 3</title>
<url>/2021/07/21/FOI2021-Summer-DAY-3/</url>
<content><![CDATA[<h2 id="数论"><a href="#数论" class="headerlink" title="数论"></a>数论</h2><p><del>小菜</del></p>
<a id="more"></a>
<h3 id="组合计数基础"><a href="#组合计数基础" class="headerlink" title="组合计数基础"></a>组合计数基础</h3><h4 id="基本计数规则"><a href="#基本计数规则" class="headerlink" title="基本计数规则"></a>基本计数规则</h4><ul>
<li>加法法则:事件A有m种产生方式,事件B有n种产生方式,则“事件A或B”有 $m+n$ 种产生方式。适用没有重叠事件的情况。</li>
<li>乘法法则:事件A有m种产生方式,事件B有n种产生方式,则“事件A或B”有 $mn$ 种产生方式。适用彼此独立的情况。</li>
</ul>
<p>一般结合使用。</p>
<ul>
<li><p>例题 1:求1400的不同的正因子个数</p>
<p> 由$1400=2^3 5^2 7$,得$n=(3+1)(2+1)(1+)=24$</p>
</li>
</ul>
<h4 id="组合计数"><a href="#组合计数" class="headerlink" title="组合计数"></a>组合计数</h4><ul>
<li><p>集合排列<br>定义 从$n$元集$S$中有序、不重复选取的$r$个元素称为$S$的一个$r$排列,$S$的所有$r$排列的数目记作 $P(n,r)$ 。</p>
<p>定理 $P(n,r)=\frac{n!}{(n-r)!},r \leq n$</p>
</li>
<li><p>集合组合<br>定义 从$n$元集$S$中无序、不重复选取的$r$个元素称为$S$的一个$r$排列,$S$的所有$r$排列的数目记作 $C(n,r)$ 。</p>
<p>定理 $C(n,r)=\frac{P(n,r)}{r!},r \leq n$</p>
<p>推论:</p>
<ol>
<li><p>$C(n,r)=\frac{n}{r}C(n-1,r-1)$</p>
</li>
<li><p>$C(n,r)=C(n,n-r)$</p>
</li>
<li><p>$C(n,r)=C(n-1,r-1)+C(n-1,r)$ 称为 $\mathrm{Pascal}$ 公式。</p>
<p> 这些性质对应了<strong>杨辉三角形</strong>。</p>
</li>
</ol>
</li>
<li><p>基本计数公式的应用</p>
<ol>
<li><p>从 $1-300$ 中任取 $3$ 个数使得其和能被 $3$ 整除的有多少种方法?</p>
<p> 解:分类选取</p>
<p> $A={1,4, \dots ,298}$</p>
</li>
</ol>
</li>
<li><p>多重集的排列</p>
<p>定理 多重集 $S={n_1a_1,n_2a_2,\dots,n_ka_k}$,$a_i$ 类有 $n_i$ 个。</p>
<ol>
<li><p>全排列 $r=n, n=\sum n_i$ </p>
<p>$$N=\frac{n!}{n_1!n_2!\dots n_k!}$$ </p>
</li>
<li></li>
</ol>
</li>
<li><p>多重集的组合</p>
<p> 定理 $S={n_1a_1,n_2a_2,\dots,n_ka_k}$,$a_i$ 类有 $n_i$ 个。$S$ 的 $r$ 组合数为 $N=C(k+r-1,r)$。</p>
<p> 证明</p>
<p> 一个 $r$ 组合为 ${x_1a_1,x_2a_2,\dots,x_ka_k}$,其实就是求方程 $x_1+x_2+\dots+x_k=r$,的非负整数解。用插板法,对应的实际上是 $S={r1,(k-1)0}$ 的全排列,也就是 $C(r,k+r-1)$;</p>
<p> 例题:</p>
<ol>
<li><p>$r$ 个相同的球放到 $n$ 个不同的盒子里,每个盒子球数不限,求放球方法数。</p>
<p> 解:实际上就是多重集的组合。</p>
<ol start="2">
<li><p>排列 $26$ 个字母,使得 $a$ 与$b$ 之间恰有 $7$ 个字母,求方法数。</p>
<p>解:简单题</p>
</li>
</ol>
</li>
</ol>
</li>
<li><p>基本计数模型</p>
<ol>
<li>$(0,0)$ 到 $(m,n)$ 的非降路径数 $\binom{n+m}{m}$。</li>
<li>$(a,b)$ 到 $(m,n)$ 的非降路径数 $\binom{n+m-a-b}{m-a}$。</li>
<li></li>
</ol>
</li>
<li><p>$\mathrm{Fibonacci}$ 数列</p>
<p>$F_1=1,F_2=2$</p>
<p>$F_i=F_{i-1}+F_{i-2},i \geq 3$</p>
</li>
<li><p>$\mathrm{Catalan}$ 数<br>一个凸 $n$ 边形的三角剖分方案数为$\mathrm{Catalan}$ 数 $h_n$。</p>
<p>$h_n= \sum_{k=2}^n b_kb_{n-k+2},h_2=1$</p>
<p>证明:</p>
<p>$h_{n+1}=\frac{1}{n} \binom{2n-2}{n-1}$</p>
<p>证明:过于复杂</p>
</li>
</ul>
<h3 id="二项式定理"><a href="#二项式定理" class="headerlink" title="二项式定理"></a>二项式定理</h3><p>定理 设 $n$ 是正整数,对一切 $x$ 和 $y$<br>$$(x+y)^n = \sum_{k=0}^n \binom{n}{k} x^ky^{n-k}$$</p>
<h4 id="变下项求和"><a href="#变下项求和" class="headerlink" title="变下项求和"></a>变下项求和</h4><p>$$\sum_{i=0}^n \binom{n}{k}=2^n$$<br>$$\sum_{i=0}^n (-1)^k \binom{n}{k}=0$$</p>
<p>证明:运用二项式定理或根据集合子集定义进行组合分析。</p>
<h4 id="变上项求和"><a href="#变上项求和" class="headerlink" title="变上项求和"></a>变上项求和</h4><h3 id="矩阵快速幂"><a href="#矩阵快速幂" class="headerlink" title="矩阵快速幂"></a>矩阵快速幂</h3><p><del>很简单,挂机了</del></p>
<h3 id="同余"><a href="#同余" class="headerlink" title="同余"></a>同余</h3><h4 id="质数"><a href="#质数" class="headerlink" title="质数"></a>质数</h4><p>只有两个正因数的正整数。</p>
<h4 id="最大公因数"><a href="#最大公因数" class="headerlink" title="最大公因数"></a>最大公因数</h4><p>$a$ 和 $b$ 的公因数中最大值称为 $a$,$b$ 的最大公因数,记作 $\gcd(a,b)$。</p>
<h4 id="同余-1"><a href="#同余-1" class="headerlink" title="同余"></a>同余</h4><p>设 $m$ 是正整数,$a$ 个 $b$ 是整数,如果 $m|a-b$ ,则称 $a$ 模 $m$ 同余与 $b$,或 $a$ 与 $b$ 模 $m$ 同余,记作$a \equiv b (\bmod m)$。</p>
<ul>
<li>例题 $3^{455}$ 的个位数是多少?(简单题)</li>
</ul>
<h4 id="一次同余方程"><a href="#一次同余方程" class="headerlink" title="一次同余方程"></a>一次同余方程</h4><p>$ax \equiv c (\bmod m),m > 0$</p>
<p>一次同余方程的解:使方程成立的整数</p>
<p>定理 整数 $a,b$ 互质的充要条件为<br>$$\exist x,y,ax+by=1$$</p>
<p>定理 方程 $ax \equiv c (\bmod m)$ 有解的充要条件是 $\gcd(a,m)|c$。</p>
<h4 id="模m逆"><a href="#模m逆" class="headerlink" title="模m逆"></a>模m逆</h4><p>如果 $ab \equiv 1 (\bmod m)$,则称 $b$ 是 $a$ 的模 $m$ 逆,记作 $a^{-1}(\bmod m)$。</p>
<p>定理:</p>
<ol>
<li>$a$</li>
<li>$a$ 的模 $m$ 逆在模 $m$ 意义下至多有一个。 </li>
</ol>
<h4 id="中国剩余定理(CRT)"><a href="#中国剩余定理(CRT)" class="headerlink" title="中国剩余定理(CRT)"></a>中国剩余定理(CRT)</h4><p>解方程组</p>
<h4 id="欧几里得算法(GCD)"><a href="#欧几里得算法(GCD)" class="headerlink" title="欧几里得算法(GCD)"></a>欧几里得算法(GCD)</h4><p><del>不会吧不会吧,不会有人到现在还不会gcd吧</del></p>
<h4 id="拓展欧几里得算法-EXGCD"><a href="#拓展欧几里得算法-EXGCD" class="headerlink" title="拓展欧几里得算法(EXGCD)"></a>拓展欧几里得算法(EXGCD)</h4><p>求二元一次不定方程的整数解。</p>
<h4 id="欧拉(Eular)定理"><a href="#欧拉(Eular)定理" class="headerlink" title="欧拉(Eular)定理"></a>欧拉(Eular)定理</h4><p>欧拉函数:</p>
<p>欧拉定理:<br>$$a^{\phi(n)}\equiv 1(\bmod n),a,n互质$$</p>
<h4 id="费马(Fermat)小定理"><a href="#费马(Fermat)小定理" class="headerlink" title="费马(Fermat)小定理"></a>费马(Fermat)小定理</h4><p>设 $p$ 是素数,$a$ 与 $p$ 互素,则<br>$$a^{p-1} \equiv 1 (\bmod p)$$</p>
<h3 id="树上高斯消元"><a href="#树上高斯消元" class="headerlink" title="树上高斯消元"></a>树上高斯消元</h3><p>????????????????????????????</p>
<h4 id="高斯消元"><a href="#高斯消元" class="headerlink" title="高斯消元"></a>高斯消元</h4><h4 id="例题-随机游走问题"><a href="#例题-随机游走问题" class="headerlink" title="例题 随机游走问题"></a>例题 随机游走问题</h4><ul>
<li><p>在一张无向连通图中,求从1点走到n点的期望步数。</p>
<p>解:记 $f_u$ 表示点 $u$ 走到 $n$ 的期望步数。对每个点建立方程。</p>
</li>
</ul>
<h4 id="例题-树上随机游走问题"><a href="#例题-树上随机游走问题" class="headerlink" title="例题 树上随机游走问题"></a>例题 树上随机游走问题</h4><ul>
<li><p>同上,图变成树。</p>
<p>解:将 $n$ 号点设为根节点,对每个点建立同样的方程,此时叶子的方程总是 $f_u=f_{father_u}+1$</p>
</li>
</ul>
<h3 id="Miller-Rabin-素性测试"><a href="#Miller-Rabin-素性测试" class="headerlink" title="Miller-Rabin 素性测试"></a>Miller-Rabin 素性测试</h3><p>不保证100%正确,<del>但是可以放心地使用!</del></p>
<ul>
<li>引理 1:费马小定理</li>
<li>引理 2:二次探测定理 如果 $p$ 是一个素数,并且 $0<x<p$,方程 $x^2 \equiv 1(\bmod p)$ 的解为 $x=1,p-1$</li>
</ul>
<p>假设 $n$ 是奇素数,则 $n-1$ 必为偶数。令 $n-1=2^qm$</p>
<p>随机</p>
<h3 id="Pollard-Rho-大整数因数分解"><a href="#Pollard-Rho-大整数因数分解" class="headerlink" title="Pollard Rho 大整数因数分解"></a>Pollard Rho 大整数因数分解</h3><p>Surrender</p>
<h3 id="卢卡斯定理"><a href="#卢卡斯定理" class="headerlink" title="卢卡斯定理"></a>卢卡斯定理</h3><p>设 $p$ 为素数。将非负整数 $a,b$ 表示为 $p$ 进制(允许前导零),$a=a_kp^k+a_{k-1}p^{k-1}+\dots+a_1p+a_0,b=b_kp^k+b_{k-1}p^{k-1}+\dots+b_1p+b_0$</p>
<p>$$C_a^b \equiv C_{a_k}^{b_k}C_{a_{k-1}}^{b_{k-1}}\dots C_{a_0}^{b_0}(\bmod p)$$</p>
]]></content>
<tags>
<tag>FOI2021</tag>
</tags>
</entry>
<entry>
<title>FOI2021 Summer DAY 4</title>
<url>/2021/07/21/FOI2021-Summer-DAY-4/</url>
<content><![CDATA[<h2 id="DP"><a href="#DP" class="headerlink" title="DP"></a>DP</h2><a id="more"></a>
<h3 id="树形DP"><a href="#树形DP" class="headerlink" title="树形DP"></a>树形DP</h3><ul>
<li><p>求树上带权最大独立集</p>
<p>解:设0为不取,1为取</p>
<p>$f(i,0)=\sum \max {f(son,1),f(son,0)}$</p>
<p>$f(i,1)=a_i + \sum f(son,0)$ </p>
</li>
</ul>
<ul>
<li><p>树上带权最大独立集且独立集大小不能超过 $m$ (树上背包)</p>
<p>解:令 $i$ 表示哪一个节点, $j$ 表示选择了多少,0表示取或不取。</p>
<p>$f(i,j,0)=\max (\sum \max {f(son,k,0),f(son,k,1)}$</p>
<p>$f(i,j,1)=a_i + \max \sum f(son,k,0)(\sum k=j-1)$</p>
</li>
</ul>
<h3 id="区间DP"><a href="#区间DP" class="headerlink" title="区间DP"></a>区间DP</h3><ul>
<li>有 $n$ 个数 $a_i$,每次操作可以将相邻两个数相加合并成一个数,直至剩下一个数,求最大得分。</li>
</ul>
<h3 id="状压DP"><a href="#状压DP" class="headerlink" title="状压DP"></a>状压DP</h3><ul>
<li><p>旅行商问题:(给定一张带权无向图,求路径最小地哈密顿回路,哈密顿回路为恰好经过图中每个点且回到原点的路径)</p>
<p>解:任选一个点作为哈密顿回路的起点,令 $f(S,i)$ 表示已经考虑好了 $S$ 集合中的点的哈密顿路径。</p>
<p>$f(S,i)=\min_{j \neq i,j \in } {f(S-2^i,j)+cost(j,i)}$</p>
</li>
<li><p>图的色数(给定一张无向图,将每个点染上一种颜色使得相邻点颜色不相同,求最少需要几种颜色)。</p>
<p>令 $f(S)$ 表示对 $S$ 集合内的点染色最小需要的颜色数。预处理出 $g(S)$ 表示 $S$ 集合是否是一个独立集。</p>
<p>$f(S)=\min_{S’ \in S,g(S’)=1} {f(S-S’)+1}$</p>
<p>时间复杂度为 $O(\sum_{i=0}^n C_n^i \times 2^i)=O(3^n)$</p>
</li>
</ul>
<h3 id="数据结构优化DP"><a href="#数据结构优化DP" class="headerlink" title="数据结构优化DP"></a>数据结构优化DP</h3><ul>
<li><p>最长上升子序列</p>
<p>令 $f(i)$ 表示以 $i$ 结尾的上升子序列长度最长是多少。</p>
<p>$f(i) =\max_{j<i,A_j<A-i} {f(j)+1}$</p>
<p>求出f(i)后在树状数组/线段树$A_i$插入 $f(i)$ 的值,查询时查询前缀最大值即可。</p>
</li>
</ul>
<h3 id="概率期望DP"><a href="#概率期望DP" class="headerlink" title="概率期望DP"></a>概率期望DP</h3><ul>
<li><p>有 $n$ 个球,每次随机抽出一个球后放回,问期望多少次才能求出每个球至少一次。</p>
<p>$f(i)$ 表示已经抽出了 $i$ 种球</p>
</li>
<li><p>给定一张有向无环简单图,初始在点 $1$,每次操作等概率随机一条出边移动直至没有出边,问停留在每个点的概率。</p>
<p>$f(i) = \sum_{(j,i) \in E} \frac{f(j)}{deg(j)}$</p>
</li>
<li><p>给定一张有向无环简单图,初始在点 $1$,每次操作等概率随机一条出边移动直至点 $n$,问移动到每一点的期望次数。</p>
<p>$f(i)=\sum_{j\neq n,(j,i)\in E}\frac{f(j)}{deg(j)} +[i=1]$</p>
<p>这样就得到了 $n-1$ 个线性方程,使用高斯消元求解即可。(感谢zmh的解释)</p>
<p>时间复杂度 $O(n^3)$</p>
</li>
</ul>
<h3 id="数位DP"><a href="#数位DP" class="headerlink" title="数位DP"></a>数位DP</h3><ul>
<li><p>求 $1$ ~ $n$ 中满足含有子串 “13” 且能被 $13$ 整除的数的个数。</p>
<p>从高位往低位考虑 $f(i,j,0/1/2,0/1)$,表示考虑到第 $i$ 位,模 $13$ 余 $j$,第三位 $0$ 表示第 $i$ 位不为 1,1表示第 $i$ 位为 $1$,$2$表示 $\leq i$ 的位存在字串“13”,第四位 $0/1$ 表示是否取到上界。</p>
<p>考虑 $f(i,j,k,l)$ 能转移给谁。枚举下一位填的数字 $d$。新的 $l’,k’$ 和 $d$ 限制由现在的得出。</p>
<p>$f(i,j,k,l)$ 可以转移给 $f(i-1,(j+d\times 10^{i-1}) \mod 13,k’,l’$</p>
<p>时间复杂度 $O(\lg n \times 13 \times 3 \times 2 \times 10)$</p>
</li>
</ul>
<h3 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h3><ul>
<li><p>agc049d Convex Sequence</p>
<p>求满足下列条件的长度为 $m$ 的非负整数序列 $a$ 的个数。</p>
<ol>
<li>$\sum_{i=1}^n A_i=m$</li>
<li>$2 \leq i \leq n-1,2a_i\leq a_{i-1}+a_{i+1}$<ul>
<li>$n,m \leq 10^5$</li>
</ul>
</li>
</ol>
<p>解:Surrender</p>
</li>
<li><p>agc022e Median Replace</p>
<p>定义一个长度为奇数 $n$ 的01串是美丽的,当且仅当每次将连续三位替换为它们的中位数 $\frac{n-1}{2}$ 此后,整个串变成一个字符1。</p>
<p>给定一个由0,1和?组成的字符串 $S$,求将问号替换为0或1后,得到一个美丽的字符串的方案数。</p>
<p>答案对 $10^9+7$ 取模。 $n \leq 2 \times 10^5$</p>
<p>解:</p>
<ol>
<li>判断已知串是否美丽,展开操作后,维护一个栈。</li>
<li>$f(i,j,k)$ 表示已经考虑了前 $i$ 位,栈中有 $j$ 个1和 $k$ 个0的方案数。</li>
</ol>
</li>
<li><p>cf585f Digits of Number Pi</p>
<p>给定一个数字串,可能存在前导零。定义一个长度为 $d$ 的数字串 $t$ 是“半出现的”,当且仅当存在一个长度至少为 $\lfloor \frac{d}{2} \rfloor$ 的 $s$ 和 $t$ 的公共子串。</p>
<p>给定两个无前导零的 $d$ 位数字 $x,y$ ,问 $[x,y]$ 中所有的整数所代表的数字串中,有多少个是“半出现的”。</p>
<p>答案对 $10^9+7$ 取模。 $1\leq |s| \leq 1000,2\leq d \leq 50,x \leq y$ 。</p>
<p>解:AC自动机树上DP,Surrender(可以与数位DP例题结合食用)。</p>
</li>
<li><p>arc108e Random IS</p>
<p>给定一个长度为 $n$ 的<br>(Surrender)</p>
</li>
<li><p>agc046d Secret Passage</p>
<p>给定一个仅包含 $0$ 和 $1$ 的字符串 $S$,求进行如下操作若干次后,能得到多少种不同的字符串:</p>
<p>删去 $S$ 中的前两个字符的其中一个,将另一个移动至 $S$ 的任意位置。</p>
<p>对 $998244353$ 取模。 $1 \leq |S| \leq 300$。</p>
</li>
<li><p>agc045c Pange Set</p>
<p>给定一个长度为 $n$ 的01串,初始时全为0。</p>
<p>以任意顺序进行若干次以下两种操作,求能得到多少种不同的字符串,对 $10^9+7$ 取模:</p>
<ol>
<li><p>选择连续 $A$ 个字符,将它们都变成 $0$ 。</p>
</li>
<li><p>选择连续 $B$ 个字符,将它们都变成 $1$ 。</p>
<p>$n\leq 5000$</p>
</li>
</ol>
</li>
<li><p>nomura2020f Sorting Game</p>
<p>有一个长度为 $m$ 的序列 $a$,值域为 $[0,x^n-1]$。</p>
<p>Snuke先进行以下操作任意次:</p>
<p>选择一个数 $d$,将序列 $a$ 中的所有数的二进制下第 $d$ 位变成0。</p>
<p>接着</p>
</li>
</ul>
]]></content>
<tags>
<tag>FOI2021</tag>
</tags>
</entry>
<entry>
<title>FOI2021 Summer DAY 5</title>
<url>/2021/07/21/FOI2021-Summer-DAY-5/</url>
<content><![CDATA[<h2 id="图论"><a href="#图论" class="headerlink" title="图论"></a>图论</h2><a id="more"></a>
<h3 id="回路"><a href="#回路" class="headerlink" title="回路"></a>回路</h3><h4 id="简单回路:"><a href="#简单回路:" class="headerlink" title="简单回路:"></a>简单回路:</h4><h4 id="欧拉回路:"><a href="#欧拉回路:" class="headerlink" title="欧拉回路:"></a>欧拉回路:</h4><p>无向联通图 $G$,有欧拉回路的充要条件是各顶点的度都是偶数。</p>
<p>必要性:一个点一定进一次,出一次,所以顶点的度一定是 $2$ 的倍数。</p>
<p>充分性:考虑构造法证明,假定一个起点,一定可以找到一个普通的简单回路。将回路从图中删去,剩下的图所有点度数都为偶数。由于图联通,剩下的图一定和此回路相交。重复此过程,并将简单回路合并,最终会获得一个欧拉回路。</p>
<p>例题 1:</p>
<blockquote>
<p>POJ1386</p>
</blockquote>
<p>考虑把字母建成点,单词之间关系连边,判断是否存在欧拉回路即可。</p>
<p>例题 2:</p>
<blockquote>
<p>给定一张混合图(既有无向边,也有有向边)的图,求欧拉回路(每一条边都只能走一次)。</p>
</blockquote>
<p>网络流?????!!</p>
<p>例题 3:</p>
<blockquote>
<p>2020 联合省选 丁香之路</p>
<p>有一个 $n$ 个点的图,$i,j$ 两点的长度为 $|i-j|$。有 $m$ 条不许经过的变。求从 $s$ 出发,到每个 $i$ 结束并且经过所有必须经过边的最小长度。</p>
<p>数据范围: $n \leq 2500,m\leq \frac{n(n-1)}{2}$。</p>
</blockquote>
<p>解:将必须要连的边连接,然后将相邻的奇点连边,最后跑最小生成树使图联通。(?)</p>
<h3 id="差分约束"><a href="#差分约束" class="headerlink" title="差分约束"></a>差分约束</h3><p>给定若干个不等式 $x_i \leq x_j + a$ ,求 $s_t-s_v$ 的最大值。</p>
<p>对于每个不等式,我们在图上从 $x_i$ 向 $x_j$ 连一条权值为 $a$ 的有向边,这个问题就转化为了求最短路的问题。</p>
<p>当这张图中存在负环时,该方程组无解。不联通时,$s_t-s_v$ 为无穷大。</p>
<p>例题 1:</p>
<blockquote>
<p>POJ3196 Layout</p>
<p>一共有 $n$ 头牛,有 $ml$ 个关系好的牛的信息,有 $md$ 个关系不好的牛的信息,关系好的两头牛之间不能超过某个距离,关系差的两头牛之间不能少于某个距离。求 $1$ 号牛和 $n$ 号牛的最大距离,无限大输出 $-2$,无解输出 $-1$。</p>
</blockquote>
<p>不用管绝对值?</p>
<p>例题 2:</p>
<blockquote>
<p>POJ1201 Intervals</p>
<p>有 $n$ 个限制,每个限制由三个数 $a_i,b_i,c_i$ 组成,表示 $[a_i,b_i]$ 中你至少需要选择 $c_i$ 个数。求最少需要选择的数的个数。</p>
</blockquote>
<p>前缀和上差分约束,简单板子题。</p>
<p>例题 3:</p>
<blockquote>
<p>XVIII Open Cup named after E.V. Pankratiev. GP of Romania. Gravity</p>
<p>给你一个 $n \times m$ ,每个位置为 <code>.</code> 或 <code>#</code> 。 <code>#</code> 构成的连通块会受重力向下掉落,直到无法掉落为止,求最后得到的矩阵。</p>
<p>数据范围: $n,m \leq 2000$</p>
</blockquote>
<p>枚举每一列,每个联通块 $s_i$ 与下面连通块 $s_j$ 有一个不等式 $s_i-s_j \geq d_j$,$d_j$ 为 $s_j$ 的当前列的厚度。</p>
<p>但是复杂度并不是很行,所以我们考虑优化建图方式。</p>
<p>对于每一个物体的,它的下落高度是相同的,所以 <code>#</code> 与 <code>#</code> 之间连一条权值为 0 的边表示相同。<code>#</code> 与 <code>.</code> 之间连一条向上为 $1$ 的边,</p>
<h3 id="连通分量"><a href="#连通分量" class="headerlink" title="连通分量"></a>连通分量</h3><h4 id="点双连通分量"><a href="#点双连通分量" class="headerlink" title="点双连通分量"></a>点双连通分量</h4><p>图 $G$ 的极大子图 $G’$,满足 $G’$ 中任意两点之间都存在两条不在除端点相交的初级路径。</p>
<h4 id="边双连通分量"><a href="#边双连通分量" class="headerlink" title="边双连通分量"></a>边双连通分量</h4><p>图 $G$ 的极大子图 $G’$,满足 $G’$ 中任意两点之间都存在两条没有公共边的初级路径。</p>
<h4 id="强连通分量"><a href="#强连通分量" class="headerlink" title="强连通分量"></a>强连通分量</h4><p>有向图 $G$ 的极大联通子图 $G’$ ,满足$G’$ 中任意两点之间都存在一条道路。</p>
<h4 id="Tarjan"><a href="#Tarjan" class="headerlink" title="Tarjan"></a>Tarjan</h4><ul>
<li>DFS树:有向图从一个点出发,按照DFS的过程可以构造出一棵DFS树,同时会产生DFS序。</li>
<li>树边</li>
<li>返祖边</li>
<li>横叉边</li>
</ul>
<p>求强连通分量:</p>
<p>如果一个点出发不能到达任何一个还没被分配到任何强连通分量里的DFS序比自己小的点。那么它和它所能到达的还没被分配到任何强连通分量的点就构成新的强连通分量。</p>
<p>求割边:</p>
<p>非树边不可能成为割边,且树边成为割边的条件是当且仅当其子树内的所有返祖边都不超过它。</p>
<p>求割点:</p>
<p>一个点所对应的某个儿子的子树中的所有返祖边都不超过该点,则这个点就是割点。</p>
<p>求点双联通分量:</p>
<p>一个点所在子树中所有返祖边均不超过这个点的父亲节点,则这个点子树中所有没有被分配到任何一个点双连通分量的边所连接的点构成一个新的点双连通分量。</p>
<p>例题 1:</p>
<blockquote>
<p>给定一张带权无向图 $G$,再给定两个点 $S,T$,求每一条边删去后 $S$ 到 $T$ 的最短路是否会增加。</p>
<p>数据范围: $n \leq 40000,m\leq 2\times 10^5$</p>
</blockquote>
<p>简单题,对最短路重建个图,然后跑个Tarjan求边双。</p>
<p>例题 2:</p>
<blockquote>
<p>网络流</p>
<p>给定一张图 $G$,图中每条边的流量为 $1$,给定 $q$ 个询问,每个询问为加一条流量为 $1$ 的边后,图中有多少个点对之间的最大流为 $1$。</p>
<p>数据范围: $n,q \leq 10^5,m \leq 5 \times 10^5$</p>
</blockquote>
<p>救命。</p>
<p>例题 3:</p>
<blockquote>
<p>Matrix</p>
<p>给定一个 $n\times n$ 的实数矩阵 $A$ ,满足 $\forall i,a_{i,i} =0, \forall i \not = j,0 \leq A_{i,j} < 1$</p>
<p>令 $E$ 为单位矩阵,即 $\forall i,a_{i,i}=1,\forall i \not = j,A_{i,j}=0$ ,求 $E-A$ 的逆矩阵中有多少个位置不为 $0$ ,数据保证矩阵有逆。</p>
<p>$n\leq 2000$</p>
</blockquote>
]]></content>
<tags>
<tag>FOI2021</tag>
</tags>
</entry>
<entry>
<title>FOI2021 Summer DAY 6</title>
<url>/2021/07/21/FOI2021-Summer-DAY-6/</url>
<content><![CDATA[<h2 id="网络流相关"><a href="#网络流相关" class="headerlink" title="网络流相关"></a>网络流相关</h2><a id="more"></a>
<h3 id="二分图"><a href="#二分图" class="headerlink" title="二分图"></a>二分图</h3><p>二分图是图论中的一种特殊模型。</p>
<p>设 $G=(V,E)$ 是一个无向图,如果顶点 $V$ 克分割为两个互不相交的子集 $(A,B)$ ,并且图中的每条边 $(i,j)$ 所关联的两个顶点 $i$ 和 $j$ 分别 $i\in A,j\in B$ ,则称图 $G 为二分图。</p>
<p>二分图中没有奇环。</p>
<h4 id="判定"><a href="#判定" class="headerlink" title="判定"></a>判定</h4><p>黑白染色即可。时间复杂度为 $O(b+m)$ 。</p>
<h4 id="二分图最大匹配——匈牙利算法"><a href="#二分图最大匹配——匈牙利算法" class="headerlink" title="二分图最大匹配——匈牙利算法"></a>二分图最大匹配——匈牙利算法</h4><p>是用来计算二分图最大匹配的一种算法。</p>
<p>如果从一个还没有被边覆盖的节点出发,不断经过没有匹配的边,匹配的边,没有匹配的边,最后经过一条没有匹配的边叫做交错路。</p>
<p>如果最后一个节点是没被匹配的节点,那么这个路叫做增广路。</p>
<p>我们将增广路上所有边翻转,很明显,我们的匹配数一定能加 $1$ 。</p>
<p><del>跑的很慢</del></p>
<h4 id="二分图最大权匹配——KM算法"><a href="#二分图最大权匹配——KM算法" class="headerlink" title="二分图最大权匹配——KM算法"></a>二分图最大权匹配——KM算法</h4><p>直接按着博客讲了,所以没有笔记<del>太有趣了</del></p>
<h3 id="网络流"><a href="#网络流" class="headerlink" title="网络流"></a>网络流</h3><p>容量网络是一个</p>
<p>网络流中,一个合法的网络流称为可行流,它应当满足:</p>
<ul>
<li>容量限制: $0\leq f(u,v)\leq c(u,v)$</li>
<li></li>
</ul>
<h4 id="最大流问题"><a href="#最大流问题" class="headerlink" title="最大流问题"></a>最大流问题</h4><p>最大流为从源点 $u$ 能同时流向 $v$ 的最大流量。</p>
<p>EK 算法</p>
<p>dinic 算法-层次网络</p>
<p>循环增广,增广的时候先分层BFS,再DFS</p>
<ol>
<li><p>分层图</p>
<p>为了避免走太长的路径浪费时间,Dinic算法每次增广前,Dinic 算法都对残量网络编号,形成层次网络。</p>
</li>
</ol>
<h3 id="费用流"><a href="#费用流" class="headerlink" title="费用流"></a>费用流</h3><h3 id="网络流与线性规划"><a href="#网络流与线性规划" class="headerlink" title="网络流与线性规划"></a>网络流与线性规划</h3>]]></content>
<tags>
<tag>FOI2021</tag>
</tags>
</entry>
<entry>
<title>FOI2021 Summer DAY 7</title>
<url>/2021/07/21/FOI2021-Summer-DAY-7/</url>
<content><![CDATA[<h2 id="计算几何"><a href="#计算几何" class="headerlink" title="计算几何"></a>计算几何</h2><a id="more"></a>
<h3 id="小知识"><a href="#小知识" class="headerlink" title="小知识"></a>小知识</h3><h3 id="向量"><a href="#向量" class="headerlink" title="向量"></a>向量</h3><h4 id="范数"><a href="#范数" class="headerlink" title="范数"></a>范数</h4><p>向量的范数为模长的平方</p>
<h4 id="运算"><a href="#运算" class="headerlink" title="运算"></a>运算</h4><ul>
<li>点乘:$a · b =x_ay_b+x_by_a$</li>
<li>叉乘:$a \times b=x_ay_b-x_by_a$</li>
<li>向量 $a$ 旋转 $$</li>
<li>判断共线:$a · b=PA \times PB =0$</li>
<li>点 $p$ 到直线 $a$ 最短距离: $|p · a|/|a|$</li>
<li>求两直线交点: 判断点是否在线段,由三角形不等式得若点 $C$ 在 $AB$ 上,则 $AC+BC=AB$</li>
<li>判断两线段是否相交:做两个边与坐标轴平行的矩形,使得这两条线段分别成为矩形的对角线,如果两个矩形不相交,则测试失败,否则接下来进行跨立实验,只需判断 $$</li>
<li>点到线段最近距离:当垂足在线段上,就是点到直线的最近距离,否则就是到线段两端点的较小值,判断</li>
</ul>
<h3 id="多边形"><a href="#多边形" class="headerlink" title="多边形"></a>多边形</h3><p>?</p>
<h3 id="凸包"><a href="#凸包" class="headerlink" title="凸包"></a>凸包</h3><p><del>很简单</del></p>
<p>算法汗牛充栋</p>
<h4 id="Graham-扫描法"><a href="#Graham-扫描法" class="headerlink" title="Graham 扫描法"></a>Graham 扫描法</h4><p>找到 $x$ 轴最小、最大的两个点,连线后,往上是上凸包,往下是下凸包。</p>
<p>先做预处理:将所有边按照 <code>x</code> 和 <code>y</code> 进行从小到大排序,对于上凸包和下凸包,分别维护一个栈,从左向右,如果当前点能和栈顶第2个包住栈顶的点,则弹出栈顶,直至满足这一条件,最后压入这个点。</p>
<h3 id="半平面交"><a href="#半平面交" class="headerlink" title="半平面交"></a>半平面交</h3><p>先尝试解决“求解一个区域可以看到给定图形的各个角落。”</p>
<p>这个区域叫做多边形的核。</p>
<h3 id="旋转卡壳"><a href="#旋转卡壳" class="headerlink" title="旋转卡壳"></a>旋转卡壳</h3><p>求凸包后,用双指针优化枚举。</p>
<h3 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h3><p>例题 1</p>
<blockquote>
<p>最小圆覆盖</p>
</blockquote>
<p>例题 2</p>
<blockquote>
<p>UVA 1303 Wall</p>
<p>给定 $n(n\leq1000)$ 个点,求出最短的包围所有点的轮廓且满足任意点到轮廓的距离不小于给定的 $L$ 。</p>
</blockquote>
<p>答案为凸包长度加上 $2\pi l$ 。</p>
<p>例题 3</p>
<blockquote>
<p>ZJOI 2008 瞭望塔</p>
<p>将H村抽象为一维的轮廓。我们可以用一条山的上方轮廓折线 $(x_1,y_1),(x_2,y_2),\dots,(x_n,y_n),x_1<x_2<\dots <x_n$ 。瞭望塔可以建造在 $[x_1,x_n]$ 间的任意位置,但是必须满足顶端可以看到可以看到H村的任意位置。求瞭望塔最小高度。</p>
</blockquote>
<p>类似于求多边形的核,获得一段新的折线,然后对于上下两段折线的折点分别求值取 $\min$ 即可。</p>
<p>例题 4</p>
<blockquote>
<p>HNOI 2008 水平可见直线</p>
</blockquote>
<p>在 $xoy$ 直角坐标平面上有 $n$ 条直线 $L_1,L_2,\dots,L_n$,若在 $y$ 值为正无穷大处往下看,能见到 $L_i$ 的某个子线段,则称 $L_i$ 为可见的,否则 $L_i$ 为被覆盖的。</p>
<p>给定 $n$ 条直线,表示</p>
<p>例题 5</p>
<blockquote>
<p>Luogu 1354</p>
<p>在一个长宽均为 $10$ ,出口入口分别为 $(0,5),(10,5)$ 的房间里,有 $n$ 堵墙,每堵墙上有两个缺口,求入口到出口的最短路径。</p>
</blockquote>
<p>缺口两端点、起点、终点之间两两判断能否连边,最后跑一遍最短路即可。</p>
]]></content>
<tags>
<tag>FOI2021</tag>
</tags>
</entry>
<entry>
<title>FOI2021 Summer DAY 8</title>
<url>/2021/07/21/FOI2021-Summer-DAY-8/</url>
<content><![CDATA[<h2 id="博弈论"><a href="#博弈论" class="headerlink" title="博弈论"></a>博弈论</h2><a id="more"></a>
<h3 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h3><p>有限的、信息公开的双人平等博弈</p>
<ol>
<li>我们的博弈游戏有一个有限状态集 $S$ ,任意时刻该博弈的状态为 $S$ 中的一个元素。</li>
<li>?</li>
<li>?</li>
<li>?</li>
<li>?</li>
</ol>
<h4 id="Nim游戏"><a href="#Nim游戏" class="headerlink" title="Nim游戏"></a>Nim游戏</h4><blockquote>
<p>有 $n$ 个石子堆,两人轮流从一个石子堆中取走任意数量(不为零)的石子。不能操作者输。</p>
<p>求先手是否有必胜策略</p>
</blockquote>
<p>后手必胜当且仅当所有石子堆的二进制异或和为 $0$ 。</p>
<h3 id="SG-函数"><a href="#SG-函数" class="headerlink" title="SG 函数"></a>SG 函数</h3><p>构造一个函数将信息公开的平等博弈映射到Nim游戏中。</p>
<p>构造 $SG(x)=mex({SG(y)}_{y\in To_x})$ 。 其中 $mex(S)=\min (N-S)$ 。</p>
<p>状态 $x$ 为必败态当且仅当 $SG(x)=0$ 。</p>
<p>对于多个游戏相加,有结论:</p>
<p>$$S_1+S_2+\dots+S_n=SG(S_1)+SG(S_2)+\dots+SG(S_n)$$</p>
<h4 id="Moore’s-Nimk"><a href="#Moore’s-Nimk" class="headerlink" title="Moore’s Nimk"></a>Moore’s Nimk</h4><blockquote>
<p>类似Nim游戏,但是每次操作可以选择 $1$~$k$ 堆取任意量的石子。</p>
</blockquote>
<h4 id="翻硬币游戏"><a href="#翻硬币游戏" class="headerlink" title="翻硬币游戏"></a>翻硬币游戏</h4><blockquote>
<p>$N$ 枚硬币排成一排,有的正面朝上,有的反面朝上。我们从左开始对硬币按 $1$ 到 $N$ 编号。</p>
<p>游戏者每次能翻 $k$ 枚硬币,但是最右边必须是从正面翻到反面。</p>
</blockquote>
<h4 id="阶梯-Nim"><a href="#阶梯-Nim" class="headerlink" title="阶梯 Nim"></a>阶梯 Nim</h4><blockquote>
<p>有 $n$ 个石子堆,可以取任意数量的石子从 $i$ 堆到 $i-1$ 堆,不能取 $1$ 堆。不能操作者输。</p>
</blockquote>
<h4 id="题目名字忘了"><a href="#题目名字忘了" class="headerlink" title="题目名字忘了"></a>题目名字忘了</h4><blockquote>
<p>有一个 $n\times m$ 的网格,每个网格上有一个非负权值,Alice可以向下或向左或向右走一个,并付出到达格子的代价,当Alice走到最后一行时,游戏结束。Bob可以选择一些格子阻止Alice从那走下。Alice想让代价尽可能小,Bob想让代价尽可能大。</p>
<p>$n,m\leq 300$</p>
</blockquote>
<p>有两个结论:</p>
<ol>
<li>Alice如果能往下走,那么一定会往下走</li>
<li>Bob一定堵Alice当前的方格。</li>
</ol>
<p>有了这两个结论,我们可以来设计DP状态。</p>
<h4 id="分石子"><a href="#分石子" class="headerlink" title="分石子"></a>分石子</h4><blockquote>
<p>给定 $n$ 堆石子,可以将一堆大于 $F$ 的堆分成任意份,但是两两石子数差不超过 $1$ 。不能操作者输。</p>
</blockquote>
<h4 id="Game-In-Darkness"><a href="#Game-In-Darkness" class="headerlink" title="Game In Darkness"></a>Game In Darkness</h4><blockquote>
<p>Alice 和 Bob 在玩游戏。两个人在树上各有一个棋子,每个人可以将棋子移动到相邻的节点。Bob被抓到就算输。Bob知道Alice接下来 $10^100$ 次方</p>
</blockquote>
<h4 id="Election-Promises"><a href="#Election-Promises" class="headerlink" title="Election Promises"></a>Election Promises</h4><blockquote>
<p>有一个DAG,每个点 $u$ 上有权值 $w_u$ 。两人轮流操作,每次操作选择一个点 $v$ 满足 $w_v>0$,将 $w_v$修改为任意非负整数 $w’_v$ ,要求 $w’+v$</p>
</blockquote>
<p>掉线了</p>
<p><del>inf^k</del> -> inf**k</p>
]]></content>
<tags>
<tag>FOI2021</tag>
</tags>
</entry>
<entry>
<title>KMP 算法</title>
<url>/2021/07/21/KMP-%E7%AE%97%E6%B3%95/</url>
<content><![CDATA[<h2 id="KMP-算法"><a href="#KMP-算法" class="headerlink" title="KMP 算法"></a>KMP 算法</h2><p>用来解决字符串问题。</p>
<a id="more"></a>
<p>考虑这样一个问题:</p>
<blockquote>
<p>给定有小写字母构成的字符串 $S$ , $T$ ,问 $T$ 在 $S$ 中是否出现过。</p>
</blockquote>
<p>朴素做法很简单,就是暴力从左到右去匹配 $T$ ,如果失败就推倒重来,这样做的时间复杂度显然是 $O(n)$ 的。</p>
<p>我们需要考虑如何优化这一过程。</p>
<p><img src="https://z3.ax1x.com/2021/07/21/Wa58OJ.png"></p>
<p>我们从位置 $1$ 开始匹配,嗯,很好,匹配上了,直到位置 $3$ 都匹配成功了,但是到了位置 $4$ 却失配了。按照暴力的做法,这个时候肯定是推倒重来,但是KMP算法却提供了一种更加优秀的解决方案。</p>
<p>我们可以维护 $T$ 串的 $nex$ 数组,$nex_i$ 表示 $T$ 串从 $1$ 到 $i$ 的最长相同前后缀。</p>
<p>当我们在位置 $4$ 失配时,我们可以看下 $nex_3$ ,发现 $1$-$1$ 和 $3$-$3$ 是相同的,那我们可以不必全部退回,而是 $T$ 串只退回到位置 $1$ 然后继续匹配 $S$ 串的位置 $4$ 。</p>
<p>在这个例子中只跳了一次 $nex$ ,但是实际上可能跳多次才能匹配成功,边界情况为 $nex_1$ 。</p>
<p>那我们如何求出 $nex$ 数组呢,核心的思想是:<strong>自己和自己匹配</strong>。</p>
<p>设当前自己匹配自己到位置 $i$ ,我们就检查位置 $nex_{i-1}+1$ 是否和 $i$ 相同,是的话,则 $nex_i=nex_{i-1}+1$ ,否则就按照KMP匹配的思路判断位置 $nex_{nex_{i-1}}$ 是否与位置 $i$ 相同,不是的话则继续向下查找,直至相同或达到边界情况 $nex_0$ 。</p>
<p>乍看之下KMP算法复杂度十分玄学,但是我们可以引入类似物理的能量守恒定理的思想,初始化时,跳 $nex$ 必须有之前的 $nex_i$ 成功赋值来提供能量,所以时间复杂度为 $O(T_{len})$,查询时也类似,时间复杂度为 $O(S_{len})$ 。综上所述,KMP算法的总时间复杂度为 $O(T_{len}+S_{len})$ 。</p>
<p>我们可以来考虑引入问题的稍微加强版的模板题。</p>
<p><a href="https://www.luogu.com.cn/problem/P3375">Luogu P3375 【模板】KMP字符串匹配
</a></p>
<blockquote>
<p>询问 $S$ 串在 $T$ 串中所有出现的位置。</p>
</blockquote>
<p>实际上我们只需要在 $S$ 匹配成功时,输出 $i-T_{len}+1$ ,并且将匹配位置挪回 $nex_{T_{len}}$ 即可。</p>
<p>代码:</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><algorithm></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cstring></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><string></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cctype></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="keyword">int</span> <span class="title">read</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">int</span> f=<span class="number">1</span>,num=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">char</span> rd=getchar();</span><br><span class="line"> <span class="keyword">while</span>(!<span class="built_in">isdigit</span>(rd)){</span><br><span class="line"> <span class="keyword">if</span>(rd==<span class="string">'-'</span>) f=<span class="number">-1</span>;</span><br><span class="line"> rd=getchar();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">while</span>(<span class="built_in">isdigit</span>(rd)){</span><br><span class="line"> num=num*<span class="number">10</span>+rd<span class="number">-48</span>;</span><br><span class="line"> rd=getchar();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> f*num;</span><br><span class="line">}</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> MAXN 1000009</span></span><br><span class="line"><span class="keyword">char</span> S[MAXN],T[MAXN];</span><br><span class="line"><span class="keyword">int</span> nex[MAXN],slen,tlen;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">begin</span><span class="params">()</span></span>{</span><br><span class="line"> slen=<span class="built_in">strlen</span>(S)<span class="number">-1</span>,tlen=<span class="built_in">strlen</span>(T)<span class="number">-1</span>;nex[<span class="number">1</span>]=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">2</span>;i<=tlen;i++){</span><br><span class="line"> <span class="keyword">int</span> now=i<span class="number">-1</span>;</span><br><span class="line"> <span class="keyword">while</span>(T[nex[now]+<span class="number">1</span>]!=T[i]&&now) now=nex[now];</span><br><span class="line"> <span class="keyword">if</span>(T[nex[now]+<span class="number">1</span>]==T[i]) nex[i]=nex[now]+<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">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%s"</span>,S+<span class="number">1</span>);S[<span class="number">0</span>]=<span class="string">'$'</span>;</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%s"</span>,T+<span class="number">1</span>);T[<span class="number">0</span>]=<span class="string">'$'</span>;</span><br><span class="line"> begin();</span><br><span class="line"> <span class="keyword">int</span> now=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=slen;i++){</span><br><span class="line"> <span class="keyword">while</span>(S[i]!=T[now+<span class="number">1</span>]&&now) now=nex[now];</span><br><span class="line"> <span class="keyword">if</span>(S[i]==T[now+<span class="number">1</span>]) now++;</span><br><span class="line"> <span class="keyword">if</span>(now==tlen){</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>,i-tlen+<span class="number">1</span>);</span><br><span class="line"> now=nex[now];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=tlen;i++) <span class="built_in">printf</span>(<span class="string">"%d "</span>,nex[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>]]></content>
<tags>
<tag>字符串</tag>
</tags>
</entry>
<entry>
<title>AC自动机</title>
<url>/2021/07/22/AC%E8%87%AA%E5%8A%A8%E6%9C%BA/</url>
<content><![CDATA[<h2 id="AC自动机"><a href="#AC自动机" class="headerlink" title="AC自动机"></a>AC自动机</h2><a id="more"></a>
<p>前置知识: KMP算法,Trie树</p>
<p>考虑这样一个<a href="https://www.luogu.com.cn/problem/P3808">问题</a>:</p>
<blockquote>
<p>给定一个匹配串 $S$ 和 $n$ 个被匹配串 $T_i$ ,求有多少串 $T_i$ 是 $S$ 的子串。</p>
</blockquote>
<p>考虑朴素做法,对每个被匹配串跑KMP算法,但是时间复杂度显然是我们无法接受的。</p>
<p>我们可以联想到有一个与字符串有关的数据结构Trie<br>树,它可以用来处理与多个字符串相关的问题。我们可以考虑将KMP移植到Trie树上。将 $nex$ 数组转化为 $fail$ 指针,在这里 $fail$ 指针指向的是当前节点表示的字符串的能在Trie树中找到的最长后缀。实际上当我们匹配到某个节点时,这个节点深度不大于这个节点 $fail$ 链上被匹配串都能被匹配。</p>
<p>接下来考虑初始化的问题。我们先对所有的匹配串建Trie树。按照KMP的思想,节点 $i$ 的fail一定是它的父亲节点深度小于于父亲节点的fail链上的节点的儿子节点。我们只需要像跳 $nex$ 数组一样跳 $fail$ 即可。因为每次查找 $fail$ 时深度一定小于自身,所以我们需要使用BFS进行初始化。</p>
<p>小知识:我们可以利用路径压缩的思想,让每次少跳 $fail$ ,我们可以直接将 $fail$ 上的儿子直接借给深度比它大的节点当作虚儿子,虚儿子可以继续借出去,当然如果这个节点有实儿子就不需要虚儿子了。<del>还是自己的儿子好</del>。</p>
<p>最后来考虑时间复杂度,初始化为 $O(\sum len(T_i) )$ ,最后查询为 $O(len(S))$ ,总时间复杂度为 $O(\sum len(T_i)+len(S))$ ,如果没有路径压缩可能常数大点。</p>
<p>代码:</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cstdio></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><algorithm></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cstring></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><queue></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><string></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cctype></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><vector></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="keyword">int</span> <span class="title">read</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">int</span> f=<span class="number">1</span>,num=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">char</span> rd=getchar();</span><br><span class="line"> <span class="keyword">while</span>(!<span class="built_in">isdigit</span>(rd)){</span><br><span class="line"> <span class="keyword">if</span>(rd==<span class="string">'-'</span>) f=<span class="number">-1</span>;</span><br><span class="line"> rd=getchar();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">while</span>(<span class="built_in">isdigit</span>(rd)){</span><br><span class="line"> num=num*<span class="number">10</span>+rd<span class="number">-48</span>;</span><br><span class="line"> rd=getchar();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> f*num;</span><br><span class="line">}</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">node</span>{</span></span><br><span class="line"> <span class="keyword">char</span> c;<span class="built_in">vector</span> <<span class="keyword">int</span>> v;</span><br><span class="line"> node *to[<span class="number">26</span>],*fail,*fa;</span><br><span class="line">}pool[<span class="number">1000090</span>],*root;</span><br><span class="line"><span class="keyword">int</span> pcnt,len,ii;</span><br><span class="line"><span class="keyword">char</span> s[<span class="number">1000090</span>];</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">build_trie_tree</span><span class="params">(node *rt,<span class="keyword">int</span> step)</span></span>{</span><br><span class="line"> <span class="keyword">if</span>(rt->to[s[step]-<span class="string">'a'</span>]==<span class="literal">NULL</span>){</span><br><span class="line"> rt->to[s[step]-<span class="string">'a'</span>]=&pool[++pcnt];</span><br><span class="line"> pool[pcnt].c=s[step];</span><br><span class="line"> pool[pcnt].fa=rt;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(step+<span class="number">1</span>==len){rt->to[s[step]-<span class="string">'a'</span>]->v.push_back(ii);<span class="keyword">return</span>;}</span><br><span class="line"> build_trie_tree(rt->to[s[step]-<span class="string">'a'</span>],step+<span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">qs</span>{</span></span><br><span class="line"> node *nw;</span><br><span class="line">};</span><br><span class="line"><span class="function">qs <span class="title">make_qs</span><span class="params">(node *a)</span></span>{</span><br><span class="line"> qs ans;</span><br><span class="line"> ans.nw=a;</span><br><span class="line"> <span class="keyword">return</span> ans;</span><br><span class="line">}</span><br><span class="line"><span class="built_in">queue</span> <qs> q;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">bfs</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i<<span class="number">26</span>;i++) <span class="keyword">if</span>(root->to[i]!=<span class="literal">NULL</span>) q.push(make_qs(root->to[i]));</span><br><span class="line"> <span class="keyword">while</span>(!q.empty()){</span><br><span class="line"> node *now=q.front().nw;</span><br><span class="line"> q.pop();</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i<<span class="number">26</span>;i++) <span class="keyword">if</span>(now->to[i]!=<span class="literal">NULL</span>) q.push(make_qs(now->to[i]));</span><br><span class="line"> <span class="keyword">if</span>(now->fa==root) now->fail=root;</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> <span class="keyword">if</span>(now->fa->fail->to[now->c-<span class="string">'a'</span>]!=<span class="literal">NULL</span>) now->fail=now->fa->fail->to[now->c-<span class="string">'a'</span>];</span><br><span class="line"> <span class="keyword">else</span> now->fail=root;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i<<span class="number">26</span>;i++) <span class="keyword">if</span>(now->to[i]==<span class="literal">NULL</span>) now->to[i]=now->fail->to[i];</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i<now->fail->v.size();i++) now->v.push_back(now->fail->v[i]);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">bool</span> book[<span class="number">1000090</span>];</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dfs</span><span class="params">(node *rt,<span class="keyword">int</span> step)</span></span>{ </span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i<rt->v.size();i++) book[rt->v[i]]=<span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">if</span>(step==len) <span class="keyword">return</span>; </span><br><span class="line"> <span class="keyword">if</span>(rt->to[s[step]-<span class="string">'a'</span>]==<span class="literal">NULL</span>) dfs(root,step+<span class="number">1</span>);</span><br><span class="line"> <span class="keyword">else</span> dfs(rt->to[s[step]-<span class="string">'a'</span>],step+<span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> n=read();root=&pool[<span class="number">0</span>];</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=n;i++){</span><br><span class="line"> ii=i;</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%s"</span>,s);</span><br><span class="line"> len=<span class="built_in">strlen</span>(s);</span><br><span class="line"> build_trie_tree(root,<span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> bfs();</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%s"</span>,s);len=<span class="built_in">strlen</span>(s);</span><br><span class="line"> dfs(root,<span class="number">0</span>);<span class="keyword">int</span> ans=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=n;i++) <span class="keyword">if</span>(book[i]) ans++;</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>]]></content>
<tags>
<tag>字符串</tag>
</tags>
</entry>
</search>