-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
1022 lines (965 loc) · 495 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
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>LCA</title>
<url>/LCA/</url>
<content><![CDATA[<h1 id="最近公共祖先-LCA-洛谷-P3379"><a href="#最近公共祖先-LCA-洛谷-P3379" class="headerlink" title="最近公共祖先 LCA 洛谷 P3379"></a>最近公共祖先 LCA 洛谷 P3379</h1><h2 id="今天-xiao-习了一下-LCA-过程十分曲折。。。"><a href="#今天-xiao-习了一下-LCA-过程十分曲折。。。" class="headerlink" title="今天 xiao 习了一下 LCA 过程十分曲折。。。"></a>今天 xiao 习了一下 LCA 过程十分曲折。。。</h2><p>(检查的时候主函数没有调用 dfs,调试了好几遍才发现。。。<br>首先,我们先来看一看定义:最近公共祖先简称 LCA(Lowest Common Ancestor)。两个节点的最近公共祖先,就是这两个点的公共祖先里面,离根最远的那个。<br>它有三种做法:</p>
<ol>
<li>暴力</li>
<li>倍增</li>
<li>树链剖分<br>遗憾的是我就会前两种;</li>
</ol>
<h2 id="第一种枚举"><a href="#第一种枚举" class="headerlink" title="第一种枚举"></a>第一种枚举</h2><p>我们有了这么一棵树,和其中的两个节点;那么我们只需要一个一个求出它们的祖先,一步步向上跳就可以找到交点,找到第一个交点就是最近公共祖先<br>显而易见,这是最为朴素的正解;<br>但不是最优解;<br>仔细一想就知道他可顶复杂度超高(给两个叶子结点最后回到根上)<br>明显过不去<br>那么就要想方设法优化</p>
<h2 id="第二种方法-倍增"><a href="#第二种方法-倍增" class="headerlink" title="第二种方法 倍增"></a>第二种方法 倍增</h2><p>倍增求 LCA 是最经典的方法了(不要问我谁提出来的问就是不知道)<br>上面朴素做法是一步一步向上跳,那么我们就可以很多步很多步向上跳,就可以优化;<br>而倍增就是优化的方法之一,以 logn 的时间复杂度来向上查询<br>只需要预处理出一个数组 f[u][i]u 是节点,i 是指 u 向上 2^i 个节点处(第 2^i 个祖先<br>那么我们就可以一步一步向上跳</p>
<h2 id="第三种方法-树链剖分"><a href="#第三种方法-树链剖分" class="headerlink" title="第三种方法 树链剖分"></a>第三种方法 树链剖分</h2><p>我不会。。。……以后再写</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> maxn 1000010</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">mm</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"> <span class="comment">/* data */</span></span><br><span class="line"> <span class="keyword">int</span> next,v;</span><br><span class="line">}cun[maxn];</span><br><span class="line"><span class="keyword">int</span> head[maxn],d[maxn],f[maxn][<span class="number">22</span>],tot;</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"><span class="function"></span>{</span><br><span class="line"> cun[++tot].next=head[x];head[x]=tot;cun[tot].v=y;<span class="comment">//结构体存链表</span></span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dfs</span><span class="params">(<span class="keyword">int</span> u,<span class="keyword">int</span> fa)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> d[u]=d[fa]+<span class="number">1</span>;<span class="comment">//子节点深度是父节点加一</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">20</span>;i++)</span><br><span class="line"> {</span><br><span class="line"> f[u][i+<span class="number">1</span>]=f[f[u][i]][i];<span class="comment">//可以自己推导(就是乘个二</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=head[u];i;i=cun[i].next)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> a=cun[i].v;<span class="comment">//邻接表向后查询</span></span><br><span class="line"> <span class="keyword">if</span>(a==fa)<span class="keyword">continue</span>;<span class="comment">//不查询父节点</span></span><br><span class="line"> f[a][<span class="number">0</span>]=u;<span class="comment">//a是u的子节点,向上跳2^0是父节点u</span></span><br><span class="line"> <span class="built_in">dfs</span>(a,u);<span class="comment">//递归</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">LCA</span><span class="params">(<span class="keyword">int</span> x,<span class="keyword">int</span> y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span>(d[x]<d[y])<span class="built_in">swap</span>(x,y);<span class="comment">//后面方便</span></span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">20</span>;i>=<span class="number">0</span>;i--)<span class="comment">//从后向前找,二进制拆分</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span>(d[f[x][i]]>=d[y])x=f[x][i];<span class="comment">//如果深度大就向上跳到相等为止</span></span><br><span class="line"> <span class="keyword">if</span>(x==y)<span class="keyword">return</span> x;<span class="comment">//如果同一深度时相等就相当于y是x的父节点</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">20</span>;i>=<span class="number">0</span>;i--)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span>(f[x][i]!=f[y][i])<span class="comment">//向上跳不相等的话就向上跳</span></span><br><span class="line"> {</span><br><span class="line"> x=f[x][i];y=f[y][i];<span class="comment">//继续</span></span><br><span class="line"> }</span><br><span class="line"> <span class="comment">/*由于向上跳容易误判,所以我们选择向上跳到同一父节点时停止,最后输出父节点</span></span><br><span class="line"><span class="comment"> 向上跳无论如何都相等时就是同一父节点了*/</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> f[x][<span class="number">0</span>];<span class="comment">//父节点便是LCA</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> n,m,s;</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"> cin>>n>>m>>s;<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><br><span class="line"> <span class="keyword">int</span> x1,y1;</span><br><span class="line"> cin>>x1>>y1;</span><br><span class="line"> <span class="built_in">add</span>(x1,y1);</span><br><span class="line"> <span class="built_in">add</span>(y1,x1);<span class="comment">//无向图需要双向添加边</span></span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">dfs</span>(s,<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><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x1,y1;</span><br><span class="line"> cin>>x1>>y1;</span><br><span class="line"> cout<<<span class="built_in">LCA</span>(x1,y1)<<endl;<span class="comment">//直接输出返回的就可以</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="尾声-Johnsonloy-的-LCA-过啦(以后会补全树链剖分的内容滴-Q-Q"><a href="#尾声-Johnsonloy-的-LCA-过啦(以后会补全树链剖分的内容滴-Q-Q" class="headerlink" title="尾声 Johnsonloy 的 LCA 过啦(以后会补全树链剖分的内容滴 Q-Q"></a>尾声 Johnsonloy 的 LCA 过啦(以后会补全树链剖分的内容滴 Q-Q</h2>]]></content>
<tags>
<tag>图</tag>
</tags>
</entry>
<entry>
<title>MST</title>
<url>/MST/</url>
<content><![CDATA[<h1 id="MST-最小生成树板子"><a href="#MST-最小生成树板子" class="headerlink" title="MST 最小生成树板子"></a>MST 最小生成树板子</h1><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>今天对我的图论知识进行了一次的扩充,最小生成树<br>前言知识:并查集,可以去翻我的博客虽然还不完善但也有一点点的用途</p>
<h2 id="kruskal-算法"><a href="#kruskal-算法" class="headerlink" title="kruskal 算法"></a>kruskal 算法</h2><h3 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h3><p>kruskal 算法由 kruskal 发明(废话),本质思想是在两个最小联通块之间找到最小的边使得这两联通快之间合并代价最小(就是边权<br>所以,kruskal 算法是一个贪心的做法<br>我们按照最小的边权一个一个加入,只要加入不产生环,就把这个点和这个边放进一个点集里<br>所以,不产生环。。。怎么做呢。。。<br>并查集咯。<br>很简单,再加入一条边的时候,就相当联通两个联通块,如果这两个联通块本来就是联合的,加入就会构成一个环<br>所以只要并查集查找这条边的两个点是不是已经被联通的了就好了<br>证明就是一个环中删掉最大的边的意思(差不多。。。可以去看 OIWIKI<br><a href="https://oi-wiki.org/graph/mst/">https://oi-wiki.org/graph/mst/</a></p>
<h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><p>P3366</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> maxn 1000010</span></span><br><span class="line"><span class="keyword">int</span> fa[maxn];</span><br><span class="line"><span class="keyword">int</span> n,m;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">mm</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"> <span class="keyword">int</span> x,y,z;</span><br><span class="line"> <span class="comment">/* data */</span></span><br><span class="line">}bian[maxn];</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">cmp</span><span class="params">(mm p,mm q)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> p.z<q.z;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">find</span><span class="params">(<span class="keyword">int</span> p)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span>(fa[p]==p)<span class="keyword">return</span> p;</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">find</span>(fa[p]);</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">merge</span><span class="params">(<span class="keyword">int</span> p,<span class="keyword">int</span> q)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> p=<span class="built_in">find</span>(p);q=<span class="built_in">find</span>(q);</span><br><span class="line"> fa[p]=q;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> ans,num;</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"> cin>>n>>m;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=m;i++)cin>>bian[i].x>>bian[i].y>>bian[i].z;</span><br><span class="line"> <span class="built_in">sort</span>(bian+<span class="number">1</span>,bian+<span class="number">1</span>+m,cmp);</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=n;i++)fa[i]=i;</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><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span>(<span class="built_in">find</span>(bian[i].x)!=<span class="built_in">find</span>(bian[i].y))</span><br><span class="line"> {</span><br><span class="line"> ans+=bian[i].z;</span><br><span class="line"> <span class="built_in">merge</span>(bian[i].x,bian[i].y);</span><br><span class="line"> <span class="keyword">if</span>(++num==n<span class="number">-1</span>){</span><br><span class="line"> cout<<ans<<endl;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> cout<<<span class="string">"orz"</span><<endl;</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>
<h2 id="prim-算法:"><a href="#prim-算法:" class="headerlink" title="prim 算法:"></a>prim 算法:</h2><p>由于本人不是很会写 prim,经常写的是 kruskal。。。所以就不给放程序这种东西了。。。不过一些思路我还是会的<br>prim 算法和 kruskal 异曲同工,不过,prim 算法不是加边,而是加点<br>prim 算法也是维护一个连通块<br>每次加进去一个距离自己最近的点,加入自己,在更新所有点的距离(重新更新<br>就像是 dijkstra。。。每次找一个最近的去更新其他的节点距离<br>所以。。。它也能堆优化<br>不过就算是堆优化也没有 kruskal 跑的快<br>所以 建议使用 kruskal</p>
<h2 id="最小生成树的延伸————次小生成树"><a href="#最小生成树的延伸————次小生成树" class="headerlink" title="最小生成树的延伸————次小生成树"></a>最小生成树的延伸————次小生成树</h2><p><del>鸽着</del></p>
]]></content>
<tags>
<tag>图</tag>
</tags>
</entry>
<entry>
<title>Tree</title>
<url>/Tree/</url>
<content><![CDATA[<h1 id="Tree-洛谷-P2619"><a href="#Tree-洛谷-P2619" class="headerlink" title="Tree 洛谷 P2619"></a>Tree 洛谷 P2619</h1><p>一道生成树的很好的题目</p>
<h2 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h2><p>给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有 need 条白色边的生成树。<br>乍一看还是很没有头绪的(反正刚开始我没有</p>
<h2 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h2><p>由于我们需要求一个最小权的,恰好有 need 条边的生成树<br>首先可以想到一个贪心的作法就是我先把最小的白边加入生成树之中直到 need 条跑 MST<br>再把黑边跑 MST 加入生成树中<br>但显然。。。这个贪心的策略非常不对。。。<br>因为白边的长度和加上黑边的长度和才会是总长度和,如果黑边要加入 2 条边,共有三条边,为 1,2,99999……黑边是会影响到白边的选取的,所以我们需要从整体上考虑问题,考虑同时加入白边黑边的时候应该如何进行选取最优<br>那我们先跑一遍 MST,求出加入的白边的个数此时加入的百变个数与 need 一定是有差别的(如果等于了直接输出就可以了)<br>我们想要从整体上考虑问题,那么我们就改变 MST 的过程就好了<br>但是怎么改变就是一个问题……<br>kruskar 的过程是要进行排序的,那我们就……改变权值就可以了呀!<br>我们将白边的权值进行改变,在每次与 need 不相符的时候就进行一次改变权值,就可以进行对百变加入生成树的过程的改变<br>如果我们将白边的权值增大以至于最小的可以加入的次小黑边,就将那条黑边加入,把这条黑边弹出,这样我们是可以获得最小的取出一条白边的代价的(因为需要一点点增加)<br>所以正解思路就具备了</p>
<h2 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h2><p>实现过程中,我们将白边的权值一点点的改变……<br>聪明的同学就想到了:<br>复杂度可能有点不对(然后开始 diss 我)<br>不要着急。。。题目中给定的边权是小于等于 100 的,我们进行二分就可以了呀<br>二分答案是一个很好的东西(虽然在这道题中不二分似乎也可以过去,我没有试验过,但是数据范围改一改就可以看到二分答案的优势了)</p>
<h2 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h2><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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> maxn 100010</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">int</span> v,e,need;</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> u,v,val,c;</span><br><span class="line">}a[maxn];</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">cmp</span><span class="params">(node a1,node a2)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span>(a1.val==a2.val)<span class="keyword">return</span> a1.c<a2.c;<span class="comment">//排序</span></span><br><span class="line"> <span class="keyword">return</span> a1.val<a2.val;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> fa[maxn];</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">find</span><span class="params">(<span class="keyword">int</span> x)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span>(x==fa[x])<span class="keyword">return</span> x;</span><br><span class="line"> <span class="keyword">return</span> fa[x]=<span class="built_in">find</span>(fa[x]);</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">merge</span><span class="params">(<span class="keyword">int</span> x,<span class="keyword">int</span> y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> x=<span class="built_in">find</span>(x);y=<span class="built_in">find</span>(y);</span><br><span class="line"> fa[x]=y;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> ans,check;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">kruskal</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> ans=<span class="number">0</span>;check=<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<=v+<span class="number">1</span>;i++)fa[i]=i;</span><br><span class="line"> <span class="keyword">int</span> cnt=<span class="number">0</span>;</span><br><span class="line"> <span class="built_in">sort</span>(a+<span class="number">1</span>,a+<span class="number">1</span>+e,cmp);</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;cnt!=v<span class="number">-1</span>;i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> aa=<span class="built_in">find</span>(a[i].u),bb=<span class="built_in">find</span>(a[i].v);</span><br><span class="line"> <span class="keyword">if</span>(aa!=bb)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span>(a[i].c==<span class="number">0</span>)check++;<span class="comment">//白边</span></span><br><span class="line"> <span class="built_in">merge</span>(aa,bb);</span><br><span class="line"> ans+=a[i].val;</span><br><span class="line"> cnt++;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//kruskal判断这一次进行MST后生成树的白边数量</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> num;</span><br><span class="line"><span class="function"><span class="keyword">signed</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"> cin>>v>>e>>need;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=e;i++)</span><br><span class="line"> {</span><br><span class="line"> cin>>a[i].u>>a[i].v>>a[i].val>>a[i].c;</span><br><span class="line"> a[i].u++;a[i].v++;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">int</span> l=<span class="number">-105</span>,r=<span class="number">105</span>;</span><br><span class="line"> <span class="keyword">while</span>(l<=r)</span><br><span class="line"> {</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">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=e;i++)</span><br><span class="line"> <span class="keyword">if</span>(!a[i].c)a[i].val+=mid;</span><br><span class="line"> <span class="built_in">kruskal</span>();</span><br><span class="line"> <span class="keyword">if</span>(check>=need){</span><br><span class="line"> l=mid+<span class="number">1</span>;</span><br><span class="line"> num=ans-need*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 class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=e;i++)</span><br><span class="line"> <span class="keyword">if</span>(!a[i].c)a[i].val-=mid;</span><br><span class="line"> <span class="comment">//对要加的长度进行二分答案,最后的结果再减去白边所加上的权值和</span></span><br><span class="line"> }</span><br><span class="line"> cout<<num<<endl;</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>
<h2 id="完结撒花"><a href="#完结撒花" class="headerlink" title="完结撒花"></a>完结撒花</h2>]]></content>
<tags>
<tag>图</tag>
</tags>
</entry>
<entry>
<title>1613</title>
<url>/P1613/</url>
<content><![CDATA[<p>P1613 跑路 一道小绿题<br>虽然这只是一道小绿题但是我觉得还是有必要总结一下的因为不错</p>
<h1 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h1><p>你有辆很 n i u b i 的汽车一秒钟可以跑 2 的任意整次方的距离<br>给你一个有向图问:从 1 跑到 n 最短时间(边权都是 1)</p>
<h1 id="先给一会思考一下"><a href="#先给一会思考一下" class="headerlink" title="先给一会思考一下"></a>先给一会思考一下</h1><h1 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h1><p>首先,题目描述就让我们很容易想到倍增这个算法<br>我们需要把所有的边都存起来<br>但是一个问题是,在有向图上倍增……会炸……<br>很容易想到如果我们进行倍增,图并不支持随机访问(不是树)显然要一个一个跳,一定会炸<br>所以:一个 dp 的思路就出来了(严格意义上的 dp,但不严格意义上我一般不把他算作 dp)<br>就是<strong>floyd</strong><br>我们考虑倍增的思想:如果我从 p 点走 2^n-1 到另一个点,再从另一个点走 2^n-1 可以走到 q 点,那就说明我们可以 p->q 走 2^n 距离(就是 1 秒)<br>那么,我们再运用 floyd 的思路,如果 j 到 i,i 到 k 都是 1 秒,那么 j 到 k 就是 1 秒<br>我们只需要再 floyd 的三重循环外面加一个循环对倍增的那一维进行判断就可以了<br>floyd 之后:<br>我们已经求出了那个点到那个点是 1 的距离,但显然我们可能不会起点到终点一定是 1s<br>所以我们需要跑最短路<br>在 floyd 求得 dis 数组的基础上,跑一遍最短路,就是最后的最短时间</p>
<h1 id="代码时间"><a href="#代码时间" class="headerlink" title="代码时间"></a>代码时间</h1><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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> maxn 70</span></span><br><span class="line"><span class="keyword">int</span> n, m;</span><br><span class="line"><span class="keyword">int</span> dis[maxn][maxn];</span><br><span class="line"><span class="keyword">int</span> f[maxn][maxn][maxn];</span><br><span class="line"><span class="function"><span class="keyword">signed</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>(dis,<span class="number">0x3f</span>,<span class="built_in"><span class="keyword">sizeof</span></span>(dis));</span><br><span class="line"> cin >> n >> m;</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><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> a, b;</span><br><span class="line"> cin >> a >> b;</span><br><span class="line"> f[a][b][<span class="number">0</span>] = <span class="number">1</span>;</span><br><span class="line"> dis[a][b] = <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> u = <span class="number">1</span>; u <= <span class="number">64</span>; u++)</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">for</span> (<span class="keyword">int</span> j = <span class="number">1</span>; j <= n; j++)</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k = <span class="number">1</span>; k <= n; k++)</span><br><span class="line"> <span class="keyword">if</span> (f[j][i][u - <span class="number">1</span>] && f[i][k][u - <span class="number">1</span>])</span><br><span class="line"> f[j][k][u] = <span class="number">1</span>,</span><br><span class="line"> dis[j][k] = <span class="number">1</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">for</span> (<span class="keyword">int</span> j = <span class="number">1</span>; j <= n; j++)</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k = <span class="number">1</span>; k <= n; k++)</span><br><span class="line"> dis[j][k] = <span class="built_in">min</span>(dis[j][k], dis[j][i] + dis[i][k]);</span><br><span class="line"> cout << dis[<span class="number">1</span>][n] << endl;</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>
<p>完结撒花<br>还蛮有意思的一道题……</p>
]]></content>
<tags>
<tag>基本算法</tag>
</tags>
</entry>
<entry>
<title>tarjan</title>
<url>/tarjan/</url>
<content><![CDATA[<h1 id="花了-3-4-天的时间干掉了这个算法:tarjan(虽然只是干掉了板子)"><a href="#花了-3-4-天的时间干掉了这个算法:tarjan(虽然只是干掉了板子)" class="headerlink" title="花了 3-4 天的时间干掉了这个算法:tarjan(虽然只是干掉了板子)"></a>花了 3-4 天的时间干掉了这个算法:tarjan(虽然只是干掉了板子)</h1><h2 id="有向图"><a href="#有向图" class="headerlink" title="有向图"></a>有向图</h2><p>我刚开始学了一天的无向图,看懂了板子之后,机房大佬告诉我先学有向图的比较好……然后就开始学有向图……<br>有向图 tarjan 的内容比较少,只有强连通分量,缩点,必经点和必经边</p>
<h3 id="前置定义"><a href="#前置定义" class="headerlink" title="前置定义"></a>前置定义</h3><p>给定一个有向图,如果在这个有向图中存在一个点,从它出发可以到达图中所有的点,那么称这个图为:<strong>流图</strong><br>我们在这个流图上进行 dfs,每个点访问一次,所有的访问的点和边构成一棵树,我们称之为<strong>搜索树</strong><br>同时,在 dfs 的过程中,我们搜到每一个点的顺序(1-N),我们把这个点按照这个顺序进行标记,这个标记我们规定它为<strong>时间戳</strong>,记为 dfn[x]<br>流图中的每一条有向边(x,y)都必然是以下四种之一: 1.树枝边:搜索树中的边,即:x 是 y 的父节点 2.前向边:x 是 y 的祖先节点但不是父节点 3.后向边:y 是 x 的祖先节点 4.横叉边:(就是除了这三种情况的边)这条边一定满足:$dfn[y] < dfn[x]$;(因为如果 dfn[x] < dfn[y]的话,y 就会成为 x 的子节点)</p>
<h3 id="强连通分量"><a href="#强连通分量" class="headerlink" title="强连通分量"></a>强连通分量</h3><p>强联通:存在路径 x->y 也存在路径 y->x 那么 x,y 强联通<br>给定一张有向图。如果对于图中任意两个节点 x,y 都满足两点强联通,那么这张有向图就是一张强连通图<br>有向图的极大强连通子图被称为强连通分量,简写为 SCC<br>那么介绍<strong>tarjan 算法</strong>:<br>一个环一定是一张强联通图。tarjan 的基本思路就是对于每一个点 x,都去寻找那些与 x 可以构成环的所有节点将他们放进一个强连通分量中去<br>容易发现:前向边没用,直接扔掉就好<br>后向边极其有用,因为有一条后向边就可以形成一个环<br>横叉边不一定,横叉边过去到另一棵子树上的节点可能是可以回去构成一个环的,也有可能并不能构成环</p>
<h4 id="栈"><a href="#栈" class="headerlink" title="栈"></a>栈</h4><p>那么我们为了让这两种边有用途,我们需要维护一个栈保存以下两类节点:</p>
<p>1.搜索树中的祖先节点<br>如果存在一条后向边,那么构成一个环</p>
<p>2.已经访问过,并且存在一条路径到达祖先节点的点(横叉边)<br>如果 z 是一个这样的点,从 z 出发存在一条路径到达祖先节点,那么如果存在一条横叉边,就可以构成一个环</p>
<p>(以下几行建议等会再食用)</p>
<p>在实现过程中,对于横叉边,我们进行遍历时,栈中剩下的节点一定是此次访问的节点,并且暂时不属于任何一个强连通分量,那么这个节点一定可以和我们当前的点形成强联通分量(因为这个节点一定可以抵达横叉边对应的边的两个端点的 lca),所以他们一定可以构成一个强连通分量……所以这就是横叉边的用途</p>
<p>进而:我们引入一个概念:追溯值</p>
<h4 id="追溯值"><a href="#追溯值" class="headerlink" title="追溯值"></a>追溯值</h4><p>x 的追溯值 low[x]定义为满足以下节点的最小的时间戳:</p>
<p>1.该点在栈中</p>
<p>2.存在一条从 subtree(x)出发的有向边,以该点为终点<br>根据定义 tarjan 算法按照以下步骤计算追溯值</p>
<p>1.当节点 x 第一次别访问到的时候,把 x 入栈,初始化 $low[x]=dfn[x]$;</p>
<p>2.扫描从 x 出发的每一条边(x,y)</p>
<p>(1)若 y 没有被访问过说明(x,y)是树枝边,递归 y:$low[x]=min(low[x],low[y])$;</p>
<p>(2)若 y 被访问过并且 y 在栈中,则令 $low[x]=min(low[x],dfn[y])$,但是请注意:在有向图的追溯值中,dfn[y]也可以改为 low[y](因为只要不一样就算进强连通分量里,详细看第三点),但由于我们的无向图 tarjan 是不能的,所以建议使用 dfn[y],不容易出锅。另外一条:y 被访问过,并且 y 在栈里,那么说明……这是一条树枝边!(如果不理解,就先记住,看完了下面你会知道为什么我会说这些的)</p>
<p><strong>3.从 x 回溯之前,判断是否有 low[x]=dfn[x]。若成立,则不断从栈中弹出节点,直至 x 出栈(这点很重要)</strong><br>童鞋们可以手摸一下,下面给一组数据:<br>1->2 2->3 3->4 4->5 5->2 1->6 6->7 7->4 6->8 8->7 8->9 9->6(编号都直接为 dfn 了,1 为根节点)<br>1:1 2:2 3:2 4:2 5:2 6:6 7:7 8:6 9:6 (追溯值)</p>
<h4 id="强连通分量的判定法则:"><a href="#强连通分量的判定法则:" class="headerlink" title="强连通分量的判定法则:"></a>强连通分量的判定法则:</h4><p>在追溯值的计算过程中,x 回溯之前 $low[x]=dfn[x]$成立,就从栈中从 x 到栈顶所有节点构成一个强连通分量<br>大致来说,在计算追溯值的第 3 步,如果 $low[x]=dfn[x]$,那么说明 subtree[x]中的所有节点不能与栈里的任何一个其他节点构成环(因为上不去)另外:横叉边的终点时间戳一定比起点时间戳小(上面有说)所以 subtree[x]中的节点不可能到达任何一个没有被访问的节点(子树)(或根节点另一个子树)<br>又因为我们及时进行了判定和出栈的操作,所以从 x 到栈顶的所有节点构成一个强连通分量,而如果这个强连通分量中的点是某一条没有被搜索到的横叉边的终点,这条横叉边的起点一定不能与这个强连通分量中的点构成强连通分量(就废了),而强连通分量中的点会被 pop 出去,所以 vis 数组会变成 0,所以可以去食用上面的三行了。<br>程序:</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"></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"><span class="function"></span>{</span><br><span class="line"> dfn[x] = low[x] = ++tim;</span><br><span class="line"> sta[++top] = x, vis[x] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = head[x]; i; i = e[i].nex)</span><br><span class="line"> <span class="keyword">if</span> (!dfn[e[i].v])</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">tarjan</span>(e[i].v);</span><br><span class="line"> low[x] = <span class="built_in">min</span>(low[x], low[e[i].v]);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (vis[e[i].v])</span><br><span class="line"> low[x] = <span class="built_in">min</span>(low[x], dfn[e[i].v]);</span><br><span class="line"> <span class="keyword">if</span> (low[x] == dfn[x])</span><br><span class="line"> {</span><br><span class="line"> cnt++;</span><br><span class="line"> <span class="keyword">int</span> y;</span><br><span class="line"> <span class="keyword">do</span></span><br><span class="line"> {</span><br><span class="line"> y = sta[top--], vis[y] = <span class="number">0</span>;</span><br><span class="line"> c[y] = cnt;</span><br><span class="line"> w[cnt] += a[y];</span><br><span class="line"> sc[cnt]++;</span><br><span class="line"> } <span class="keyword">while</span> (x != y);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>由于我们的强连通分量是每一个点都可以互相到达的,那么我们科室适当的考虑一下能不能把这几个点看成一个点来进行问题的处理,这样我们就可以引入一个概念叫做:<strong>缩点</strong></p>
<p>我们可以吧每一个 SCC 缩成一个点,对于原图中的每一条有向边,如果 $c[x]!=c[y]$,则在编号为 c[x]和 c[y]的 SCC 之间连上一条边,最后我们会得到一张 DAG(有向无环图)<br>下面的程序对 SCC 进行缩点操作:以洛谷缩点板子题为例 P3387</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">add_c</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> ed[++totd] = {y, hd[x]};</span><br><span class="line"> hd[x] = totd;</span><br><span class="line">}</span><br><span class="line"><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><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = head[i]; j; j = e[j].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (c[i] == c[e[j].v])</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> in[c[e[j].v]] += <span class="number">1</span>;<span class="comment">//这个是统计入度,因为需要用到拓扑排序</span></span><br><span class="line"> <span class="built_in">add_c</span>(c[i], c[e[j].v]);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="有向图的必经点和必经边"><a href="#有向图的必经点和必经边" class="headerlink" title="有向图的必经点和必经边"></a>有向图的必经点和必经边</h3><p>给一张有向图,起点为 S 终点为 T,若从 S 到 T 的每一条路径都经过一个点或者一条边,那它就被称为 S 到 T 的必经点或必经边<br>Lenguar-tarjan 算法通过计算支配树求出必经点集,但是…………板子题是黑题,我还是不想了<br>但是还是有方法计算有向无环图的必经点必经边的:</p>
<p>1.在原图的拓扑序上进行 DP,求出 S 到点 x 的路径条数 fs[x]</p>
<p>2.在返图上再次 DP 计算从点 x 到终点 T 的路径条数 ft[x]<br>显然根据乘法原理: 1.对于一条有向边来说(x,y)若 $fs[x]*fs[y]=fs[T]$,则(x,y)是必经边 2.对于一个点 x,若 $fs[x]*ft[x]=fs[T]$则 x 是必经点</p>
<h3 id="有向图写完了,就该进行无向图的博客之旅了!(前方道路淤堵。。。请保持好车距。。。)"><a href="#有向图写完了,就该进行无向图的博客之旅了!(前方道路淤堵。。。请保持好车距。。。)" class="headerlink" title="有向图写完了,就该进行无向图的博客之旅了!(前方道路淤堵。。。请保持好车距。。。)"></a>有向图写完了,就该进行无向图的博客之旅了!(前方道路淤堵。。。请保持好车距。。。)</h3><h2 id="无向图"><a href="#无向图" class="headerlink" title="无向图"></a>无向图</h2><p>无向图的知识前端部分比较简单,因为我们有了有向图的基础<br>但是后面就会有一点难咯</p>
<h3 id="无向图的割点与桥"><a href="#无向图的割点与桥" class="headerlink" title="无向图的割点与桥"></a>无向图的割点与桥</h3><p>0<br>给定一张无向连通图<br>若删去其中一个节点和与它相连的所有边之后,这张图分裂成两个或两个以上的不相连的子图,则称 x 为 G 的割点<br>若删去其中一条边之后,这张图分裂成两个不相连的子图,则称 e 为 G 的桥或割边<br>Tarjan 大佬做过的贡献:斐波那契堆(毒瘤东西)、Splay Tree(毒瘤东西)、Lint-Cut Tree(已经被踢出考纲的东西)等。。。</p>
<p><strong>时间戳</strong><br>在图的 dfs 过程中,按照没一个节点第一次被访问的时间顺序进行标记(参照有向图时间戳)</p>
<p><strong>搜索树</strong><br>参照有向图搜索树(上面有)</p>
<h4 id="追溯值-1"><a href="#追溯值-1" class="headerlink" title="追溯值"></a>追溯值</h4><p>重要的东西,和有向图有一点点不一样<br>low[x]定义为以下节点的时间戳的最小值:<br>1.subtree(x)中的节点 2.通过 1 条不在搜索树上的边能够到达 subtree(x)的节点<br>初始化:low[x]=dfn[x]<br>如果在搜索树上 x 是 y 的父节点,$low[x]=min(low[x],low[y])$<br>如果(x,y)不是搜索树上的边则 $low[x]=min(low[x],dfn[y])$<br>除了根节点之外,一条边如果不是搜索树上的边,那么这一条边一定能与其他节点构成一个环(树嘛,这个轻轻想想就知道了)</p>
<h4 id="割边判定法则:"><a href="#割边判定法则:" class="headerlink" title="割边判定法则:"></a>割边判定法则:</h4><p>无向边(x,y)是桥,当且仅当搜索数上存在 x 的一个子节点 y,满足:</p>
<p>$$dfn[x] < low[y]$$</p>
<p>根据定义 dfn[x] < low[y]说明从 subtree(y)出发,在不经过(x,y)的情况下,是无法达到搜索树上 x 或者是比 x 更早访问的节点的 <strong>(如果一条不是搜索树上的边(x,y)(x < y),那么 y 一定在 x 的子树里,所以我访问一定只会访问到比自己 dfn 小的点(大的也会访问但是没用)</strong> 所以若是删去这条边,subtree(y)就好像形成了一个封闭的环境,与节点 x 没有边相连接<br>读者不难发现:桥一定是搜索树上的边,并且一个简单环中的边一定不是桥<br>下面的程序求出一张无向图中所有的桥。特别注意:(x,y)是不能用来更新 low 数组的,所以我们可以进行父节点的标记<br>但是如果这样是处理不了重边的,那么我们考虑,改为记录进入没一个节点的边的编号:<br>边我们用链式前向星进行存储的时候我们会发现一条是会被记录两次的,所以如果将编号为 i 的边进行了标记,我们还需要将编号为 i^1 的边进行标记</p>
<p>代码:</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"></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 class="keyword">int</span> in_edge)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> dfn[x] = low[x] = ++tim;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = head[x]; i; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (!dfn[e[i].y])</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">tarjan</span>(e[i].y, i);</span><br><span class="line"> low[x] = <span class="built_in">min</span>(low[x], low[e[i].y]);</span><br><span class="line"> <span class="keyword">if</span> (dfn[x] < low[e[i].y])</span><br><span class="line"> bridge[i] = bridge[i ^ <span class="number">1</span>] = <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (i != (in_edge ^ <span class="number">1</span>))</span><br><span class="line"> low[x] = <span class="built_in">min</span>(low[x], dfn[e[i].y]);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">signed</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"> ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line"> cin >> n >> m;</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><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x, y;</span><br><span class="line"> cin >> x >> y;</span><br><span class="line"> <span class="built_in">add</span>(x, y);</span><br><span class="line"> <span class="built_in">add</span>(y, x);</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><br><span class="line"> <span class="keyword">if</span> (!dfn[i])</span><br><span class="line"> <span class="built_in">tarjan</span>(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 < tot; i += <span class="number">2</span>)</span><br><span class="line"> <span class="keyword">if</span> (bridge[i])</span><br><span class="line"> cout << e[i ^ <span class="number">1</span>].y << <span class="string">' '</span> << e[i].y << endl;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h4 id="割点判定法则"><a href="#割点判定法则" class="headerlink" title="割点判定法则"></a>割点判定法则</h4><p>如果 x 不是搜索树的根节点的话,那么 x 是割点当且仅当搜索树中存在 x 的一个子节点 y,满足:<br>dfn[x]<=low[y]<br>特别的,如果 x 是根节点,那么 x 是割点当且仅当搜索树上存在至少两个子节点 y1,y2 满足条件<br><strong>证明:</strong><br><strong>不给,自己证去(模仿割边)</strong>lueluelue<br>下面给程序体会一下<br>洛谷板子题 P3388</p>
<p>代码:</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><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"><span class="function"></span>{</span><br><span class="line"> dfn[x] = low[x] = ++tim;</span><br><span class="line"> <span class="keyword">int</span> flag = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = head[x]; i; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].v;</span><br><span class="line"> <span class="keyword">if</span> (!dfn[v])</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">tarjan</span>(v);</span><br><span class="line"> low[x] = <span class="built_in">min</span>(low[x], low[v]);</span><br><span class="line"> <span class="keyword">if</span> (dfn[x] <= low[v])</span><br><span class="line"> {</span><br><span class="line"> flag++;</span><br><span class="line"> <span class="keyword">if</span> (flag > <span class="number">1</span> || x != root)</span><br><span class="line"> cut[x] = <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> low[x] = <span class="built_in">min</span>(low[x], dfn[v]);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">signed</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"> ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line"> cin >> n >> m;</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><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x, y;</span><br><span class="line"> cin >> x >> y;</span><br><span class="line"> <span class="keyword">if</span> (x == y)</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> <span class="built_in">add</span>(x, y);</span><br><span class="line"> <span class="built_in">add</span>(y, x);</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><br><span class="line"> <span class="keyword">if</span> (!dfn[i])</span><br><span class="line"> root = i, <span class="built_in">tarjan</span>(i);</span><br><span class="line"> <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><br><span class="line"> <span class="keyword">if</span> (cut[i])</span><br><span class="line"> ans++;</span><br><span class="line"> cout << ans << endl;</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> (cut[i])</span><br><span class="line"> cout << i <<<span class="string">' '</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>
<h3 id="无向图的双连通分量"><a href="#无向图的双连通分量" class="headerlink" title="无向图的双连通分量"></a>无向图的双连通分量</h3><p>若一张无向连通图不存在割点,则称它为“点双连通图”,类比,不存在割边即为“边双连通图”<br>极大点双联通子图被称为点双连通分量简写为“v-DCC”,极大变双联通子图被称为边双连通分量<br>简称为“e-DCC”<br><strong>定理</strong>:<br>一张无向图是“点双连通分量”: 1.图的顶点不超过 2 2.图中的任意两点都通是包含在至少一个简单环中,简单环是指不自交的环<br>“边双连通分量”<br>当且仅当任意一条边都包含在至少一个简单环中</p>
<h4 id="e-DCC-的求法:"><a href="#e-DCC-的求法:" class="headerlink" title="e-DCC 的求法:"></a>e-DCC 的求法:</h4><p>求出无向图中所有的桥,删去</p>
<p>代码:</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="comment">//加到原来的割边程序</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dfs</span><span class="params">(<span class="keyword">int</span> x)</span></span></span><br><span class="line"><span class="function"><span class="comment">//进行dfs遍历一遍图,不经过桥边和已经被标记过的节点,如果经过桥边那么说明跨越了两个不一样的e-DCC</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> c[x] = dcc;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = head[x]; i; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> y = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (c[y] || bridge[y])</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> <span class="built_in">dfs</span>(y);</span><br><span class="line"> }</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">int</span> i = <span class="number">1</span>; i <= n; i++)</span><br><span class="line"> <span class="keyword">if</span> (!c[i])</span><br><span class="line"> ++dcc, <span class="built_in">dfs</span>(i);<span class="comment">//dfs遍历</span></span><br></pre></td></tr></table></figure>
<h4 id="e-DCC-的缩点"><a href="#e-DCC-的缩点" class="headerlink" title="e-DCC 的缩点"></a>e-DCC 的缩点</h4><p>把每一个 e-DCC 看作一个节点,把桥边看做链接编号为 c[x],c[y]的 e-DCC 对应的节点的无向边,会产生一棵树</p>
<p>代码:</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">add_edge</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> edge[++tot_edge] = {y, head_edge[x]};</span><br><span class="line"> head_edge[x] = tot_edge;</span><br><span class="line">}</span><br><span class="line"><span class="comment">//main里的</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= tot; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x = e[i].y, y = e[i ^ <span class="number">1</span>].y;</span><br><span class="line"> <span class="keyword">if</span> (c[x] == c[y])</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> <span class="built_in">add_edge</span>(x, y);<span class="comment">//对每一条边进行扫描(双向边就进行两次扫描)只要扫描到了就添加进去</span></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 < tot_edge; i += <span class="number">2</span>)</span><br><span class="line"> cout << edge[i ^ <span class="number">1</span>].y << <span class="string">' '</span> << edge[i].y << endl;</span><br></pre></td></tr></table></figure>
<h4 id="v-DCC-的求法"><a href="#v-DCC-的求法" class="headerlink" title="v-DCC 的求法"></a>v-DCC 的求法</h4><p>“点双连通分量”是一个极其容易误解的概念,不能直接删除割点<br>如果某一个节点是孤立点,则它自己单独构成一个 v-DCC。除了孤立点之外,v-DCC 的大小至少为 2。<br>虽然桥并不属于任何一个 v-DCC,但是一个割点可能会属于多个 v-DCC。<br>为了求出“点双连通分量”,我们需要在 Tarjan 算法的过程中维护一个栈,并按照如下的方法维护栈中的元素</p>
<p>1.当一个节点第一次被访问的时候,把这个节点入栈</p>
<p>2.当割点判定法则$dfn[x]<=low[y]$成立的时候,无论 x 是否为根,都需要</p>
<p>(1)从栈顶不断弹出节点直至 y 被弹出<br>(2)被弹出的所有点和 x 一起构成一个 v-DCC</p>
<p>代码:</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"></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"><span class="function"></span>{</span><br><span class="line"> dfn[x] = low[x] = ++tim;</span><br><span class="line"> <span class="keyword">int</span> flag = <span class="number">0</span>;</span><br><span class="line"> sta[++top] = x;<span class="comment">//这是比割点板子多了的一步栈</span></span><br><span class="line"> <span class="keyword">if</span> (x == root && !head[x])<span class="comment">//孤立点直接跳过</span></span><br><span class="line"> {</span><br><span class="line"> dcc[++cnt].<span class="built_in">push_back</span>(x);</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">int</span> i = head[x]; i; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].v;</span><br><span class="line"> <span class="keyword">if</span> (!dfn[v])</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">tarjan</span>(v);</span><br><span class="line"> low[x] = <span class="built_in">min</span>(low[x], low[v]);</span><br><span class="line"> <span class="keyword">if</span> (dfn[x] <= low[v])</span><br><span class="line"> {</span><br><span class="line"> cnt++;</span><br><span class="line"> flag++;</span><br><span class="line"> <span class="keyword">if</span> (flag > <span class="number">1</span> || x != root)</span><br><span class="line"> cut[x] = <span class="number">1</span>;</span><br><span class="line"> <span class="comment">//接下来是进行加入v-DCC的过程</span></span><br><span class="line"> <span class="keyword">int</span> y;</span><br><span class="line"> <span class="keyword">do</span></span><br><span class="line"> {</span><br><span class="line"> y = sta[--top];</span><br><span class="line"> dcc[cnt].<span class="built_in">push_back</span>(y);</span><br><span class="line"> } <span class="keyword">while</span> (y != v);</span><br><span class="line"> <span class="comment">//跳栈,在第一次搜到就进行跳栈(由于加入栈之后x不一定上面的点就是当前的v所以要从栈顶跳到y之后再加入x节点)(因为一个割点可能同时是很多个V-DCC之中的)</span></span><br><span class="line"> dcc[cnt].<span class="built_in">push_back</span>(x);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> low[x] = <span class="built_in">min</span>(low[x], dfn[v]);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">signed</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"> ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line"> cin >> n >> m;</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><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x, y;</span><br><span class="line"> cin >> x >> y;</span><br><span class="line"> <span class="keyword">if</span> (x == y)</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> <span class="built_in">add</span>(x, y);</span><br><span class="line"> <span class="built_in">add</span>(y, x);</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><br><span class="line"> <span class="keyword">if</span> (!dfn[i])</span><br><span class="line"> root = i, <span class="built_in">tarjan</span>(i);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= cnt; i++)</span><br><span class="line"> {</span><br><span class="line"> cout<<i<<<span class="string">": "</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> j=<span class="number">0</span>;j<dcc[i].<span class="built_in">size</span>();j++)cout<<dcc[i][j]<<<span class="string">' '</span>;</span><br><span class="line"> cout<<endl;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h4 id="v-DCC-的缩点"><a href="#v-DCC-的缩点" class="headerlink" title="v-DCC 的缩点"></a>v-DCC 的缩点</h4><p>v-DCC 的缩点比 e-DCC 复杂一点,因为一个割点可能会同时属于多个 v-DCC,设途中 p 割割点和 t 割 v-DCC。我们建立一张包含 p+t 个节点的新图,把每一个 v-DCC 和每一个割点都作为新图中的节点,并在每一个割点与包含他的所有 v-DCC 之间连边,这会构成一棵树</p>
<p>代码:</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">int</span> num_ed=cnt,new_id[maxn];</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><br><span class="line"> <span class="keyword">if</span>(cut[i])new_id[i]=++num_ed;</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<=cnt;i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> j=<span class="number">0</span>;j<dcc[i].<span class="built_in">size</span>();j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x=dcc[i][j];</span><br><span class="line"> <span class="keyword">if</span>(cut[x])</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">add_c</span>(i,new_id[x]);</span><br><span class="line"> <span class="built_in">add_c</span>(new_id[x],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<tot_edge;i+=<span class="number">2</span>)</span><br><span class="line"> cout<<edge[i^<span class="number">1</span>].v<<<span class="string">' '</span><<edge[i].v<<endl;</span><br></pre></td></tr></table></figure>
<h2 id="无向图也写完了"><a href="#无向图也写完了" class="headerlink" title="无向图也写完了"></a>无向图也写完了</h2><h1 id="完结撒花"><a href="#完结撒花" class="headerlink" title="完结撒花"></a>完结撒花</h1>]]></content>
<tags>
<tag>图</tag>
</tags>
</entry>
<entry>
<title>前缀和与差分</title>
<url>/%E5%89%8D%E7%BC%80%E5%92%8C%E4%B8%8E%E5%B7%AE%E5%88%86/</url>
<content><![CDATA[<h1 id="对前缀和与差分进行总结,来源:洛谷题单"><a href="#对前缀和与差分进行总结,来源:洛谷题单" class="headerlink" title="对前缀和与差分进行总结,来源:洛谷题单"></a>对前缀和与差分进行总结,来源:洛谷题单</h1><h1 id="首先"><a href="#首先" class="headerlink" title="首先"></a>首先</h1><p>(由于之前教练和我说可以刷一刷洛谷的题单刷刷基础我就去了</p>
<h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><h2 id="前缀和有几种,一维和二维的用的比较多。"><a href="#前缀和有几种,一维和二维的用的比较多。" class="headerlink" title="前缀和有几种,一维和二维的用的比较多。"></a>前缀和有几种,一维和二维的用的比较多。</h2><p>一维前缀和比较简单,直接将数组的前几个加起来成一个单独的数组就可以<br>二维前缀和有点不一样:我们的二维前缀和处理的过程中不能直接通过上一个得到(需要三步操作其实也相当于直接得到。。。<br>在进行循环的时候,我们可以设想一下:<br>1 2 3<br>1 2 3<br>1 2 3<br>的前缀和 f[2][3]等于什么<br>显然它可以从 f[2][2]和 f[1][3]转移过来<br>但是都不一样 f[2][2]+f[1][3]会把 f[1][2]算两次<br>所以……减一下就可以<br>方程:f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-1];<br>就可以进行处理了</p>
<h3 id="二维前缀和的例题:洛谷-P2004-领地选择"><a href="#二维前缀和的例题:洛谷-P2004-领地选择" class="headerlink" title="二维前缀和的例题:洛谷 P2004 领地选择"></a>二维前缀和的例题:洛谷 P2004 领地选择</h3><p><a href="https://www.luogu.com.cn/problem/P2004">题目链接</a><br>一道模板题。。。<br>处理二维前缀和,四个角顶点 x1,x2,y1,y2(x1<x2,y1<x2)ans=max(ans,f[x2][y2]-f[x1][y2]-f[x2][y1]+f[x1][y1]);<br>怎么推导意会一下就可以很简单</p>
<h2 id="差分"><a href="#差分" class="headerlink" title="差分"></a>差分</h2><p>差分是一种很妙的算法,有的时候他可以自己单独成题,有的时候也可以配合着前缀和<br>因为:前缀和与差分是一对逆操作,前缀和序列差分一下就是原序列,差分序列前缀和一下也是原序列</p>
<h3 id="例题-1-IncDec-Sequence-CH0304(简称:蓝书例题)"><a href="#例题-1-IncDec-Sequence-CH0304(简称:蓝书例题)" class="headerlink" title="例题 1 IncDec Sequence CH0304(简称:蓝书例题)"></a>例题 1 IncDec Sequence CH0304(简称:蓝书例题)</h3><p>给定一个长度为 n(1e5)的序列,每次可以选择一个区间+1 或者-1<br>求至少多少次可以让序列所有数相等,再求,最少次数之下,序列最后多少种可能的值<br>序列所有数都相等代表了:差分序列除了第一个之外都为 0<br>那么:我们让差分序列 b 的 bn+1=0,每一次进行区间加减的时候都代表着我们要对差分序列中的两个数一个+1 另一个-1;<br>我们的目的是让 b2~bn 变成 0.<br>由于加一减一都是可以的,那么我们就没有区间进行加减时是否需要考虑+1 在前还是-1 在前这个限制了<br>(之前考试的时候有一道题是只给减法的,就比这个难一点,但其实也就相当于是特判,不难)<br>我们可以进行分类讨论: 1.选 bi,bj,在一个正另一个负的时候多进行操作 2.选 b1,bj,1 选完之后考虑 3.选 bi,bn+1,同样是 1 选完之后考虑<br>4.b1,bn+1,没有意义,舍去(因为 b1,bn+1 并不会对序列造成影响<br>第 1 类操作我们可以直接进行判断,判断序列中正数负数的绝对值,这两个的差就是 1 的次数<br>而第二第三次直接判断剩下的就可以,因为 2,3 操作事实上等价<br>综上所述,这个题第一问的答案就是两个数绝对值最大的那个(正负数分别的和的 max)<br>而第二问:因为是要求最小次数,操作一的次数等无影响,反正都会消耗完<br>那就考虑第 2,3 次操作的次数<br>如果我们第 2,3 次操作次数为 m<br>我们就可以进行选择进行那次操作,每次选择操作会不一样,但既然是问值,那就询问差分序列的第一个值<br>考虑操作 2,每一次的操作 2 都会对 b1 进行更改,操作 2 至少 0 次,最多 m 次,共 m+1 中可能<br>m=max(p,q)-min(p,q)<br>完美解决。。。</p>
<h3 id="例题-2-洛谷-P2671-求和"><a href="#例题-2-洛谷-P2671-求和" class="headerlink" title="例题 2 洛谷 P2671 求和"></a>例题 2 洛谷 P2671 求和</h3><p>前缀和好题<br><a href="https://www.luogu.com.cn/problem/P2671">题目链接</a><br>我们先考虑题中给的三元组(x,y,z)<br>y-x=z-y 那么说明,x,z 同奇或者同偶<br>既然如此,我们考虑对 color 下手:<br>每一个 color 的奇数偶数分别存储,他们中的每一个都可以单独构成一个三元组<br>三元组的分数:<br>编号之和乘数字之和<br>如果一个一个找,复杂度会炸<br>那么我们就可以看看这个分数能不能下手:显然可以<br>(x+z)<em>(numx+numz)=x</em>numx+z<em>numx+numz</em>x+z<em>numz<br>在每一个三元组,我们的 x</em>numx 都会被算到,那就统计一下三元组的个数,运用结合律把这么多的三元组进行结合律<br>我们数列中的元素回合所有其他的元素构成一个三元组从而被算一次(不管比他小还是比他大)<br>元素还会和其他元素的 num 都乘一次<br>那么我们处理 cnt 数组(就是记录 color 奇数偶数的那个)乘奇偶数的前缀和减去当前的数加上 cnt 数组乘当前的数字<br>这道题就被巨佬的您切掉了</p>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>总之前缀和与差分是可以用到很多的地方的<br>插粉还可以用在你自己想要的区间求和<br>比如你想让一段序列都加都减,直接在差分序列上改一改最后求一个前缀和就可以了<br>很 nice</p>
<h1 id="完结撒花"><a href="#完结撒花" class="headerlink" title="完结撒花"></a>完结撒花</h1>]]></content>
<tags>
<tag>基本算法</tag>
</tags>
</entry>
<entry>
<title>常中集训</title>
<url>/%E5%B8%B8%E4%B8%AD%E9%9B%86%E8%AE%AD/</url>
<content><![CDATA[<h1 id="2-21"><a href="#2-21" class="headerlink" title="2.21"></a>2.21</h1><h2 id="Problem-A:count"><a href="#Problem-A:count" class="headerlink" title="Problem A:count"></a>Problem A:count</h2><blockquote>
<p>有一张n个点m条边的无向图。记$C_1$为这个图导出子图为 $K_4$的数量 ,$C_2$为补图导出子图为$K_4$的数量 ( $K_4$是4个点的完全图)</p>
<p>请你求出$C_1-C_2$的值.</p>
<p>n<=5e4,m<=1e5</p>
</blockquote>
<p><strong>前置知识:三元环计数,组合计数(一点点),容斥(思想),<del>脑子</del></strong></p>
<p>我们考虑这样一件事情:求出C2是很简单的,直接容斥:</p>
<p>我们设F0为四个点中至少有0条边的方案数,F1,F2……F6(最多6条边)</p>
<p>那C2不就是F0-F1+F2-F3+F4-F5+F6,然而我们仔细观察会发现……</p>
<p>F6不就是C1?那我们将式子进行移项就变成了:</p>
<p>C2-C1=F0-F1+F2-F3+F4-F5,(取个相反数不就行了)</p>
<p>然后我们转化完题意就可以进行计算了:</p>
<p><strong>细节看代码,有注释</strong><del>我就口胡一遍</del></p>
<ul>
<li><p>$F0$ 就等于N选4</p>
</li>
<li><p>$F1$ 就等于一条边,再从剩下的点中随便选出来两个(因为不一定有连边)</p>
</li>
<li><p>$F2$ 分两种情况:1.两条边有公共端点 2.没有公共端点,这样也好说,先枚举一条边,寻找与它没有公共端点的边,然后枚举公共点,计算出边</p>
</li>
<li><p>$F3$ 分几种情况:1.三元环2.一个点连着三条边3.一条链</p>
</li>
<li><p>$F4$ 也好说,1.三元环上连一条边挂上一个点2.四元环</p>
</li>
<li><p>$F5$ 需要脑子里想一下:只有一种情况就是两个有公共边的三元环</p>
</li>
</ul>
<h3 id="代码(含注释)"><a href="#代码(含注释)" class="headerlink" title="代码(含注释)"></a>代码(含注释)</h3><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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> LL long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">1e5</span> + <span class="number">10</span>;</span><br><span class="line">vector<<span class="keyword">int</span>> G[maxn], g[maxn];</span><br><span class="line"><span class="keyword">int</span> cnt[maxn];</span><br><span class="line"><span class="keyword">int</span> d[maxn];</span><br><span class="line"><span class="keyword">int</span> n, m;</span><br><span class="line"><span class="keyword">int</span> x, y;</span><br><span class="line"><span class="keyword">int</span> X[maxn], Y[maxn];</span><br><span class="line"><span class="keyword">int</span> rk[maxn];</span><br><span class="line"><span class="keyword">int</span> vis[maxn], c[maxn];</span><br><span class="line"><span class="keyword">int</span> id[maxn];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">cmp</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (d[x] == d[y])</span><br><span class="line"> <span class="keyword">return</span> x > y;</span><br><span class="line"> <span class="keyword">return</span> d[x] < d[y];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function">LL <span class="title">f0</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1ll</span> * n * (n - <span class="number">1</span>) * (n - <span class="number">2</span>) * (n - <span class="number">3</span>) / <span class="number">24</span>; <span class="comment">// n选4</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function">LL <span class="title">f1</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1ll</span> * m * (n - <span class="number">2</span>) * (n - <span class="number">3</span>) / <span class="number">2</span>; <span class="comment">//一条边两端随便选点(不重复</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function">LL <span class="title">f2</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> LL res = <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><br><span class="line"> res += m - (d[X[i]] + d[Y[i]] - <span class="number">1</span>); <span class="comment">//枚举边,寻找与它没有公共点的边</span></span><br><span class="line"> <span class="built_in">assert</span>(res % <span class="number">2</span> == <span class="number">0</span>); <span class="comment">//不知道有什么用——johnsonloy</span></span><br><span class="line"> res /= <span class="number">2</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"> res += (n - <span class="number">3</span>) * <span class="number">1ll</span> * d[i] * (d[i] - <span class="number">1</span>) / <span class="number">2</span>; <span class="comment">//有公共点</span></span><br><span class="line"> <span class="comment">//枚举公共点为i,那么两条边连的点方案数就是d[i]*(d[i]-1)/2,由于我们要求的是K4的个数所以还需要乘(n-3)</span></span><br><span class="line"> <span class="keyword">return</span> res;</span><br><span class="line">}</span><br><span class="line"><span class="function">LL <span class="title">f3</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> LL res = <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"> vis[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 <= n; ++i)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j : G[i])</span><br><span class="line"> {</span><br><span class="line"> c[j] = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">if</span> (rk[i] > rk[j])</span><br><span class="line"> vis[j] = <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">0</span>; j < G[i].<span class="built_in">size</span>(); ++j)</span><br><span class="line"> <span class="keyword">if</span> (rk[i] > rk[x = G[i][j]])</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k = <span class="number">0</span>; k < G[x].<span class="built_in">size</span>(); ++k)</span><br><span class="line"> <span class="keyword">if</span> (rk[x] > rk[y = G[x][k]] && vis[y])</span><br><span class="line"> {</span><br><span class="line"> ++res;</span><br><span class="line"> ++cnt[g[x][k]];</span><br><span class="line"> ++cnt[g[i][j]];</span><br><span class="line"> ++c[y];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">0</span>; j < G[i].<span class="built_in">size</span>(); ++j)</span><br><span class="line"> <span class="keyword">if</span> (rk[i] > rk[x = G[i][j]])</span><br><span class="line"> cnt[g[i][j]] += c[x], vis[x] = c[x] = <span class="number">0</span>; <span class="comment">//清空,覆盖次数</span></span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//求三元环的个数,还顺便求了一下每一条边被三元环覆盖的次数</span></span><br><span class="line"> res = res * (n - <span class="number">6</span>); <span class="comment">//第四个点,但是这里是乘的 n-6,是因为后面求链式结构的时候会多算三元环的情况,要减去,就直接加在这里了,这里是不管第四个点和另外三个点有没有边的,因为后面容斥会有减去</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"> res += <span class="number">1ll</span> * d[i] * (d[i] - <span class="number">1</span>) * (d[i] - <span class="number">2</span>) / <span class="number">6</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 <= m; ++i)</span><br><span class="line"> res += <span class="number">1ll</span> * (d[X[i]] - <span class="number">1</span>) * (d[Y[i]] - <span class="number">1</span>); <span class="comment">//一条链的时候,就是一条边的两端点各自找另外一个点</span></span><br><span class="line"> <span class="comment">//减掉三个三元环个数,因为每一个三元环的三条边在统计的时候都会再算一遍三元环,所以要减3</span></span><br><span class="line"> <span class="keyword">return</span> res;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function">LL <span class="title">f4</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> LL res = <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"> vis[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 <= n; ++i)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j : G[i])</span><br><span class="line"> <span class="keyword">if</span> (rk[i] > rk[j])</span><br><span class="line"> vis[j] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j : G[i])</span><br><span class="line"> <span class="keyword">if</span> (rk[i] > rk[j])</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k : G[j])</span><br><span class="line"> <span class="keyword">if</span> (rk[j] > rk[k] && vis[k])</span><br><span class="line"> res += d[i] + d[j] + d[k] - <span class="number">6</span>; <span class="comment">// 三元环上面挂着一个点的方案数</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j : G[i])</span><br><span class="line"> vis[j] = <span class="number">0</span>; <span class="comment">//清空</span></span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// cerr << "res1 " << res <<'\n';</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"> c[i] = <span class="number">0</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><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j : G[i])</span><br><span class="line"> <span class="keyword">if</span> (rk[i] > rk[j])</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k : G[j])</span><br><span class="line"> <span class="keyword">if</span> (rk[i] > rk[k])</span><br><span class="line"> res += c[k], ++c[k]; <span class="comment">//四元环计数,两边两条边</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j : G[i])</span><br><span class="line"> <span class="keyword">if</span> (rk[i] > rk[j])</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k : G[j])</span><br><span class="line"> c[k] = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> res;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function">LL <span class="title">f5</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> LL res = <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><br><span class="line"> res += cnt[i] * (cnt[i] - <span class="number">1</span>) / <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">return</span> res; <span class="comment">//这一条边被多少个三元环覆盖了,那么我们就可以直接计算出来五条边是多少方案</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">signed</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"> ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line"> cin >> n >> m;</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><br><span class="line"> {</span><br><span class="line"> cin >> X[i] >> Y[i];</span><br><span class="line"> d[X[i]]++, d[Y[i]]++;</span><br><span class="line"> G[X[i]].<span class="built_in">push_back</span>(Y[i]);</span><br><span class="line"> G[Y[i]].<span class="built_in">push_back</span>(X[i]);</span><br><span class="line"> g[X[i]].<span class="built_in">push_back</span>(i);</span><br><span class="line"> g[Y[i]].<span class="built_in">push_back</span>(i);</span><br><span class="line"> <span class="comment">// G是出边,g是点所对的边的编号</span></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><br><span class="line"> id[i] = i; <span class="comment">//为了后面排序做准备</span></span><br><span class="line"> <span class="built_in">sort</span>(id + <span class="number">1</span>, id + n + <span class="number">1</span>, cmp);</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"> rk[id[i]] = i; <span class="comment">//排序</span></span><br><span class="line"> <span class="comment">//按照边的度数进行排序</span></span><br><span class="line"> LL v0 = <span class="built_in">f0</span>(), ans1 = <span class="built_in">f1</span>(), ans2 = <span class="built_in">f2</span>(), ans3 = <span class="built_in">f3</span>(), ans4 = <span class="built_in">f4</span>(), ans5 = <span class="built_in">f5</span>();</span><br><span class="line"> LL ans = v0 - ans1 + ans2 - ans3 + ans4 - ans5;</span><br><span class="line"> cout << -ans << <span class="string">'\n'</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">10 32 3 8 9 10 2 9 1 10 5 8 1 3 2 6 3 6 2 3 7 10 4 7 2 4 3 7 5 7 3 10 1 7 7 9 4 10 8 9 3 9 4 6 2 10 1 9 2 8 4 8 5 6 8 10 6 7 4 9 5 9 4 5 6 9</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure>
<h2 id="Problem-B-geometry"><a href="#Problem-B-geometry" class="headerlink" title="Problem B geometry"></a>Problem B geometry</h2><p>平面几何……算了</p>
<h2 id="Problem-C-赌怪"><a href="#Problem-C-赌怪" class="headerlink" title="Problem C 赌怪"></a>Problem C 赌怪</h2><p>概率期望,算了</p>
<h1 id="2-22"><a href="#2-22" class="headerlink" title="2.22"></a>2.22</h1><h2 id="T1-排列"><a href="#T1-排列" class="headerlink" title="T1 排列"></a>T1 排列</h2><blockquote>
<p>对于一个1,2,…,n的排列a,我们会为它定义一个贡献:</p>
<p><img src="C:\Users\DEll\AppData\Roaming\Typora\typora-user-images\image-20220312191911719.png" alt="image-20220312191911719"></p>
<p>现在我们会随机生成一个排列,我们希望知道排列的贡献的期望是多少。 </p>
<p>$n<=1e7,1<=k<=5,1e8<p<2^{31}$</p>
</blockquote>
<p><strong>容斥大好题啊!</strong></p>
<p>首先观察式子,会有贡献的$i$条件就是比两边都小;难点在于那个 k 次幂如何处理。</p>
<p>可以想象这样一件事,我们将有贡献的$i$单独拿出 ,然后相当于在这些拿出来的位置每次随便选一个,</p>
<p>如此 k 次,方案数就是那个式子。</p>
<p>考虑选到的位置组成一个集合,由于可以选择重复的位置,所以集合大小是小于等于 k 的。</p>
<p>将 ($i,a_i$)投影到平面上,而一个$i$合法就是 \/ 的形状。</p>
<p>可以发现形成了类似 …\/\/…\/\/\/…\/… 的形状(称为锯齿形,点代表不选),而每一个最低点就是满足条件的$i$。</p>
<p>考虑计算出每一串连起来的锯齿形的方案数,然后 dp 拼凑起来计数。</p>
<p>怎么算 给 $2q+1$个数,将它们填入长度为 $2q+1$的序列并且投影满足锯齿形 的方案数呢?</p>
<p>很简单。可以发现 $q<=k<=5$,所以在另一个程序打一个暴力就可以算出来了:</p>
<p>前面是$2q+1$,后面的是$ans$。</p>
<p>$3:2<del>5:16</del>7:272<del>9:7936</del>11:353792$</p>
<p>有了这个之后题目就很简单了,我们使用 dp 计算出 $f[i][j][k]~,i,j,k$ 分别表示选择的位置的个数(可能选择重复的位置)(根据youwike所说i也可以说是块数)(代码注释有解释),所有锯齿的总长度,锯齿的数量。</p>
<p>(上面的是题解的内容)</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"><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 class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">20</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxm = <span class="number">1e7</span> + <span class="number">10</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> n, k, mod;</span><br><span class="line"><span class="keyword">int</span> f[maxn][maxn][maxn];</span><br><span class="line"><span class="keyword">int</span> inv[maxm], jie[maxm];</span><br><span class="line"><span class="keyword">int</span> num[maxn];</span><br><span class="line"><span class="keyword">int</span> g[] = {<span class="number">0</span>, <span class="number">2</span>, <span class="number">16</span>, <span class="number">272</span>, <span class="number">7936</span>, <span class="number">353792</span>};</span><br><span class="line"><span class="comment">// g函数代表的是,有i个波谷形状时的方案数</span></span><br><span class="line"><span class="comment">//暴力dp做法:设f[i][j]代表我放了后i个数(从大到小放),总共有j个波谷的方案数,由于我向波谷两旁放置最小的数时波谷数量并不会发生变化,所以不应该在波谷两旁放,然而波谷两旁总共有j*2个位置,所以我们可以从f[i-1][i-2*j]转移,产生贡献</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">qpow</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> sum = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (y)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (y & <span class="number">1</span>)</span><br><span class="line"> sum = sum * x % mod;</span><br><span class="line"> x = x * x % mod;</span><br><span class="line"> y >>= <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> sum;</span><br><span class="line">}</span><br><span class="line"><span class="comment">//快速幂</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">C</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (y > x - y)</span><br><span class="line"> y = x - y;</span><br><span class="line"> <span class="keyword">int</span> res = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = x - y + <span class="number">1</span>; i <= x; i++)</span><br><span class="line"> res = res * i % mod;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= y; i++)</span><br><span class="line"> res = res * inv[i] % mod;</span><br><span class="line"> <span class="keyword">return</span> res;</span><br><span class="line">}</span><br><span class="line"><span class="comment">//组合数</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dp</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> f[<span class="number">0</span>][<span class="number">0</span>][<span class="number">0</span>] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> ku = <span class="number">1</span>; ku <= <span class="number">5</span>; ku++)</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= <span class="number">5</span>; i++) <span class="comment">//块的种类(块最多只有5种</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">2</span> * i + <span class="number">1</span>; j <= <span class="number">15</span>; j++)</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> ge = i; ge <= <span class="number">5</span>; ge++)</span><br><span class="line"> f[ku][j][ge] = (f[ku][j][ge] + f[ku - <span class="number">1</span>][j - <span class="number">2</span> * i - <span class="number">1</span>][ge - i] * <span class="built_in">C</span>(j, <span class="number">2</span> * i + <span class="number">1</span>) % mod * g[i] % mod) % mod;</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">dp的过程:</span></span><br><span class="line"><span class="comment">首先我们设f[ku][j][ge]表示:我们选出ku个块(每一段连续的,首尾相接的V字形为一个块,块的总长度为j,块中总共有ge个V字形的总方案数</span></span><br><span class="line"><span class="comment">那我们的转移就变成了前一个块向当前块转移,然后我们枚举块的种类(一个波谷两个波谷……),2*i+1是块的长度</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">init</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> jie[<span class="number">0</span>] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= <span class="number">100</span>; i++)</span><br><span class="line"> inv[i] = <span class="built_in">qpow</span>(i, mod - <span class="number">2</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= <span class="number">10000000</span>; i++)</span><br><span class="line"> jie[i] = jie[i - <span class="number">1</span>] * i % mod;</span><br><span class="line">}</span><br><span class="line"><span class="comment">//预处理</span></span><br><span class="line"><span class="function"><span class="keyword">signed</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="comment">//我们把题目转化为在所有的V字形中选出来k个V字形,可以选重复的的方案数,那么显然就是选一个的方案数的k次方</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 >> n >> k >> mod;</span><br><span class="line"> <span class="built_in">init</span>();</span><br><span class="line"> <span class="built_in">dp</span>();</span><br><span class="line"> num[<span class="number">0</span>] = <span class="number">1</span>;</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><br><span class="line"> num[i] = <span class="built_in">qpow</span>(i, k);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">1</span>; j < i; j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> ((i - j) & <span class="number">1</span>)</span><br><span class="line"> num[i] = (num[i] - <span class="built_in">C</span>(i, j) * <span class="built_in">qpow</span>(j, k) % mod + mod) % mod;</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> num[i] = (num[i] + <span class="built_in">C</span>(i, j) * <span class="built_in">qpow</span>(j, k) % mod + mod) % mod;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//由于我们在进行处理的时候,我们钦定了有i个V字形是必须要选的,那么我们就必须选上这几个V字形,这代表着我们需要进行容斥,如果说我们现在要钦定3个V,但是钦定了5次,那我们就需要容斥一遍,让每一个V都正好被钦定了1次</span></span><br><span class="line"> <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 <= <span class="number">5</span>; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">1</span>; j <= <span class="number">15</span>; j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> p = <span class="number">1</span>; p <= <span class="number">5</span>; p++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (n >= j)</span><br><span class="line"> {</span><br><span class="line"> ans = (ans + f[i][j][p] * num[p] % mod * <span class="built_in">C</span>(n, j) % mod * <span class="built_in">C</span>(n - j + i, i) % mod * jie[n - j] % mod) % mod;</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="comment">//f[i][j][p]代表意义上面dp过程是有的,乘容斥过程的数,C(n,j)代表的是在长度为n的原序列中选出来j的位置,C(n-j+i,i)代表我要将现在的序列插进原来的n-j的序列里的方案数,jie[n-j]是剩下的n-j个数的排列方案</span></span><br><span class="line"> <span class="comment">//由于我们在每一次算数的时候,都是以k次方为限制的,所以我们并不需要担心算重这一回事</span></span><br><span class="line"> cout << (ans * <span class="built_in">qpow</span>(jie[n], mod - <span class="number">2</span>)) % mod << endl;<span class="comment">//jie[n]是算期望</span></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h2 id="T2-填数游戏"><a href="#T2-填数游戏" class="headerlink" title="T2 填数游戏"></a>T2 填数游戏</h2><p>……最小直径生成树,算了</p>
<h2 id="T3-练功"><a href="#T3-练功" class="headerlink" title="T3 练功"></a>T3 练功</h2><p>倒着处理的干活……</p>
<p>(太长太麻烦的题……)<del>我不是很想写</del></p>
<blockquote>
<p>小B有一台巨大的计算机,每当输入一个整数,这台计算机就会输出一个整数。为了理清这台庞大计算机的结构,小B将这台计算机的计算过程分为n个函数,每一个函数都有一个参数s,一开始第i个函数的参数为i 。 </p>
<p>对于一个带有参数s的函数,如果输入的数为x,那么它会实现以下过程: </p>
<p>1.如果x不为s的倍数,则将x加1。 </p>
<p>2.如果x为s的倍数,那么返回 x+s,函数结束。 </p>
<p>每一个函数输出的数将会成为下一个函数输入的数,计算机输出的数即为第n个函数的返回值。 </p>
<p>但光是这样并不能真正发挥这台计算机的强大功能,小B希望你能够帮他实现两个操作:</p>
<p><em>1.</em> <strong>l r</strong> : 将第<strong>l</strong>个函数到第<strong>r</strong>个函数翻转,注意参数连同函数一起翻转。 </p>
<p><em>2.</em> <strong>st c</strong> : 当从第<strong>st</strong>个函数输入一个<strong>c</strong>时,求整个计算机输出的值为多少?</p>
<p>$0≤c≤min(n^2,10^12);1≤st≤n;1≤l≤r;1≤n≤3*10^6;1≤q≤3000$</p>
</blockquote>
<p>听说这个东西要用到整除分块(啊其实还是听youwike说的)</p>
<p>推 <del>手膜</del> 了20分钟,弄出来一个性质:(在不进行反转的情况下)在进行了一定次数之后,我们输出的结果和我们当前的数的商,在一个区间内不变,可以合并(用整除分块)</p>
<p>翻转的情况:</p>
<p>我们可以对一个单调递增,递减的序列进行维护,每一次翻转都只会增加两个新区间</p>
<p>我们考虑对于一个原来的区间:[L,R],如果我们输入的是$c_1$,输出的是$c_2$,那么意味着:反转之后输入的是$-C_2$输出的是$-C_3,C_3$是不比$C_1$小的第一个能够被R整除的数</p>
<p>那么我们倒推,如果第i+1个函数增加x次,那么第i个函数大概会增加$\frac{i+1}{i}*x$次</p>
<p>也可以进行合并处理所有$\frac{x}{i}$相等的项,种类数不超过20000种(然而我并不会证明)</p>
<h1 id="2-23"><a href="#2-23" class="headerlink" title="2.23"></a>2.23</h1><p>只会T1</p>
<h2 id="T1-拆分"><a href="#T1-拆分" class="headerlink" title="T1 拆分"></a>T1 拆分</h2><blockquote>
<p>现有一整数 <em>n</em>,求满足以下条件的整数序列个数:</p>
<p>• $a_1 + a_2 + · · · + a_m = n$ </p>
<p>• $0 < a_1 ≤a_2 ≤ · · · ≤a_m$ </p>
<p>• $∀i\neq j~~|a_i-a_j|\ge k$ </p>
<p>• $h_m~ mod~ p = 1$</p>
<p>$1 ≤ n ≤ 10^6, 0 ≤ k ≤ n, 1 ≤ p ≤ k + 1$</p>
</blockquote>
<p><strong>啊我只会90分的做法</strong></p>
<p>我们看题可以知道,这个序列是递增的,相邻两个数之间的差至少为k</p>
<p>那么我们考虑一个dp:数的划分</p>
<p>由于每两个数之间的差至少为k,那么我们先将所有的数减去相应的k*(i-1)</p>
<p>最后被减去的就是$i*(i-1)*k/2$</p>
<p>观察发现,如果k>0的话,i绝对不会超过$2*\sqrt{n}$的</p>
<p>所以最后复杂度就是$n*\sqrt{n}$级别(k=0的时候就是$n^2$</p>
<p>那么我们进行dp:</p>
<p>设$f[i][j]$表示前i个数,总和为j,那么我们可以认为$f[i][j]$可以通过$f[i-1][j-1],f[i][j-i]$转移过来</p>
<p>含义是:我们在这个序列的最后一位上添加上一个1或者将这个数列的所有数+1,事实证明可以遍历所有情况</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">1e6</span> + <span class="number">10</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> mod = <span class="number">998244353</span>;</span><br><span class="line"><span class="keyword">int</span> n, k, p;</span><br><span class="line"><span class="keyword">int</span> h[maxn];</span><br><span class="line"><span class="keyword">int</span> f[<span class="number">2</span>][maxn];</span><br><span class="line"><span class="keyword">int</span> ans;</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> scan</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">template</span> <<span class="keyword">typename</span> T></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="keyword">void</span> <span class="title">read</span><span class="params">(T &x)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> x = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">char</span> c = <span class="built_in">getchar</span>();</span><br><span class="line"> <span class="keyword">int</span> f = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (; !<span class="built_in">isdigit</span>(c); c = <span class="built_in">getchar</span>())</span><br><span class="line"> f |= c == <span class="string">'-'</span>;</span><br><span class="line"> <span class="keyword">for</span> (; <span class="built_in">isdigit</span>(c); c = <span class="built_in">getchar</span>())</span><br><span class="line"> x = x * <span class="number">10</span> + (c ^ <span class="number">48</span>);</span><br><span class="line"> <span class="keyword">if</span> (f)</span><br><span class="line"> x = -x;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">template</span> <<span class="keyword">typename</span> T, <span class="keyword">typename</span>... Args></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="keyword">void</span> <span class="title">read</span><span class="params">(T &x, Args &...args)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="built_in">read</span>(x), <span class="built_in">read</span>(args...);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">template</span> <<span class="keyword">typename</span> T></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="keyword">void</span> <span class="title">write</span><span class="params">(T x, <span class="keyword">char</span> ch)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (x < <span class="number">0</span>)</span><br><span class="line"> <span class="built_in">putchar</span>(<span class="string">'-'</span>), x = -x;</span><br><span class="line"> <span class="keyword">static</span> <span class="keyword">short</span> st[<span class="number">30</span>], tp;</span><br><span class="line"> <span class="keyword">do</span></span><br><span class="line"> st[++tp] = x % <span class="number">10</span>, x /= <span class="number">10</span>;</span><br><span class="line"> <span class="keyword">while</span> (x);</span><br><span class="line"> <span class="keyword">while</span> (tp)</span><br><span class="line"> <span class="built_in">putchar</span>(st[tp--] | <span class="number">48</span>);</span><br><span class="line"> <span class="built_in">putchar</span>(ch);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> scan;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">MOD</span><span class="params">(<span class="keyword">int</span> &x)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (x > mod)</span><br><span class="line"> x -= mod;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">signed</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">read</span>(n, k, p);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < p; i++)</span><br><span class="line"> <span class="built_in">read</span>(h[i]);</span><br><span class="line"> f[<span class="number">0</span>][<span class="number">0</span>] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>, now = <span class="number">1</span>; i * (i - <span class="number">1</span>) * k / <span class="number">2</span> + i <= n; i++, now ^= <span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x = i * (i - <span class="number">1</span>) * k / <span class="number">2</span>;</span><br><span class="line"> <span class="built_in">memset</span>(f[now], <span class="number">0</span>, <span class="built_in"><span class="keyword">sizeof</span></span>(f[now]));</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = i; j + x <= n; j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">MOD</span>(f[now][j] = (f[now][j - i] + f[now ^ <span class="number">1</span>][j - <span class="number">1</span>]));</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (h[i % p])</span><br><span class="line"> ans += f[now][n - x], <span class="built_in">MOD</span>(ans);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">write</span>(ans, <span class="string">'\n'</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="T2-集合"><a href="#T2-集合" class="headerlink" title="T2 集合"></a>T2 集合</h2><p>值域扫描线一类的东西,题解没看懂……</p>
<h2 id="T3-网格"><a href="#T3-网格" class="headerlink" title="T3 网格"></a>T3 网格</h2><p>稳定匹配(等我把网络流搞完)</p>
<h1 id="2-24-(这两天太难了水了一会)"><a href="#2-24-(这两天太难了水了一会)" class="headerlink" title="2.24 (这两天太难了水了一会)"></a>2.24 (这两天太难了水了一会)</h1><p>一道都不会……</p>
<p>吐槽出题人太喜欢甘雨了。。。出了三道甘雨</p>
<h2 id="T1-藏弓待用"><a href="#T1-藏弓待用" class="headerlink" title="T1 藏弓待用"></a>T1 藏弓待用</h2><p>动态dp加分块优化空间</p>
<h2 id="T2-山泽麟迹"><a href="#T2-山泽麟迹" class="headerlink" title="T2 山泽麟迹"></a>T2 山泽麟迹</h2><p>树上的高斯消元……</p>
<h2 id="T3-降众天华"><a href="#T3-降众天华" class="headerlink" title="T3 降众天华"></a>T3 降众天华</h2><p>高斯整数gcd+平面几何</p>
<h1 id="2-25"><a href="#2-25" class="headerlink" title="2.25"></a>2.25</h1><p>(其实还没来得及改呢现在马上下课了)(再说了我也不会改啊)</p>
<h2 id="T1-给国与地震"><a href="#T1-给国与地震" class="headerlink" title="T1 给国与地震"></a>T1 给国与地震</h2><p>启发式合并?还是说可并堆一类的东西</p>
<h2 id="T2-给国与时光机"><a href="#T2-给国与时光机" class="headerlink" title="T2 给国与时光机"></a>T2 给国与时光机</h2><p>大构造。。。没听懂</p>
<h2 id="T3-给国与赌场"><a href="#T3-给国与赌场" class="headerlink" title="T3 给国与赌场"></a>T3 给国与赌场</h2><p>集训队学长表示不会做。。。甚至没看懂题解。。。</p>
]]></content>
<tags>
<tag>SCZ</tag>
</tags>
</entry>
<entry>
<title>并查集</title>
<url>/%E5%B9%B6%E6%9F%A5%E9%9B%86/</url>
<content><![CDATA[<h1 id="并查集"><a href="#并查集" class="headerlink" title="并查集"></a>并查集</h1><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>今天根据书上的指引,想要学习最小生成树,然而蒟蒻在 OI WIKI 上学习的时候被告知:<br>前置章节是并查集。。。<br>于是蒟蒻便用了一天的时间 A 了三道黄题一道蓝题(其实相当于一道黄题……<br>所以今天蒟蒻过来总结一番</p>
<h2 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h2><p>并查集是一种树形结构,通过名字我们可以知道:<br>并:合并,查:查询,集:集合<br>就是合并和查询一个集合<br>也可以相当于是联通块之间的判断。<br>我们把一个联通快之间的点放入一个点集之中,<br>并查集就可以查询这个点是不是在集合中(不知道集合的去预(复)习高一课本</p>
<h2 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h2><p>我们看一个故事:<br>几个家族进行宴会,但是家族普遍长寿,所以人数众多。由于长时间的分离以及年龄的增长,这些人逐渐忘掉了自己的亲人,只记得自己的爸爸是谁了,而最长者(称为「祖先」)的父亲已经去世,他只知道自己是祖先。为了确定自己是哪个家族,他们想出了一个办法,只要问自己的爸爸是不是祖先,一层一层的向上问,直到问到祖先。如果要判断两人是否在同一家族,只要看两人的祖先是不是同一人就可以了。<br>(来自于 OI WIKI)<br>我们的并查集就相当于是这个故事中的实现过程:<br>建立一棵树,将父亲自己的儿子放进儿子节点中<br>每次询问两个人是在哪一个家族(树)之中,就询问自己的父亲是否在家族(树)之中<br>如果两个人的某个祖先(c++意义上)相等,就相当于他们两个是在一个家族中的<br>但是,有一次,两个祖先对话,想将各自的家族合并到一起,这该怎么办。。。<br>好办!将一个祖先的爸爸改成另一个祖先就可以了,反正我们不在乎某一个节点的爸爸究竟是谁,显然我们只在乎两个人是否是同一个家族也就是需不需要去一(de)起(guo)祭(gu)拜(ke)。</p>
<h2 id="朴素"><a href="#朴素" class="headerlink" title="朴素"></a>朴素</h2><p>查找:<br>就像上述操作一样,建立一棵树,将某些儿子们放进并查集,访问就可以知道是那颗树<br>合并:<br>也像上面一样,改父亲<br>在最开始的时候,我们是不知道谁是谁的爸爸的,那么就让他们每一个人都是一个小家族,当我们知道了谁是谁的爸爸之后,进行一次合并操作,就可以让两个人变成同一个祖先<br>但是,如果每一次查找都要向上跳到最上面的祖先或者每一次合并都需要合并 n/2 个点,那么复杂度将会是巨大的。。。</p>
<h2 id="优化"><a href="#优化" class="headerlink" title="优化"></a>优化</h2><h3 id="路径压缩"><a href="#路径压缩" class="headerlink" title="路径压缩"></a>路径压缩</h3><p>路径压缩,顾名思义,就是将并查集查询的路径进行压缩<br>我们上面说到了,每一次查找都需要向上进行跳跃,一直跳到祖先一样(其实一般都需要直接爬到最上面<br>这样的复杂度真的很大<br>定义中说的是:我们要判断联通块,那么我们就把所有的儿子节点直接连向树根<br>之后再去判断就只需要 O(1)时间查询祖先了(虽然在预处理的时候不是 O1 但也快了不少</p>
<h3 id="启发式合并"><a href="#启发式合并" class="headerlink" title="启发式合并"></a>启发式合并</h3><p>说实话我不知道为什么要去这个名字,感觉很难受并且我找不到名字和操作之中的关系<br>上面有说到,我们在合并的时候,是要将一个祖先改成另一个祖先的儿子的<br>那么如果 n 个点,n-1 个点是一个集合,1 个点是一个集合,我们将它合并,要把 n-1 个点的爸爸都改一改,会很累<br>但如果我们把 1 个点的祖先更改,就会很简单的呢!(假装很厉害的样子<br>所以,每一次我们进行合并之前,都记录一下联通块的点数<br>每一次合并取一次 min,就会优化</p>
<h3 id="注:"><a href="#注:" class="headerlink" title="注:"></a>注:</h3><p>其实启发式合并有没有无所谓,有的时候还可能增加你的时间复杂度(其实可能就是一个常数<br>在不用启发式合并只用路径压缩的复杂度其实也就是 mlogn 甚至说 ma(m,n)。。。<br>(所以我不会写启发式合并</p>
<h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><p>代码就以洛谷的板子了 P3367</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> maxn 100010</span></span><br><span class="line"><span class="keyword">int</span> fa[maxn];<span class="comment">//父节点</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">find</span><span class="params">(<span class="keyword">int</span> x)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">//查找</span></span><br><span class="line"> <span class="keyword">if</span>(fa[x]!=x)fa[x]=<span class="built_in">find</span>(fa[x]);</span><br><span class="line"> <span class="keyword">return</span> fa[x];</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">unionset</span><span class="params">(<span class="keyword">int</span> x,<span class="keyword">int</span> y)</span><span class="comment">//合并</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> x=<span class="built_in">find</span>(x);</span><br><span class="line"> y=<span class="built_in">find</span>(y);</span><br><span class="line"> fa[x]=y;<span class="comment">//祖先的更改</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,m;</span><br><span class="line"> cin>>n>>m;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=n;i++)fa[i]=i;</span><br><span class="line"> <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<=m;i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x,y,z;</span><br><span class="line"> cin>>z>>x>>y;</span><br><span class="line"> <span class="keyword">if</span>(z==<span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">unionset</span>(x,y);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(z==<span class="number">2</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span>(<span class="built_in">find</span>(x)==<span class="built_in">find</span>(y))cout<<<span class="string">'Y'</span><<endl;</span><br><span class="line"> <span class="keyword">else</span> cout<<<span class="string">'N'</span><<endl;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>是不是非常的简单。。。<br>我反正是这么觉得的。。。<br>时间复杂度:<a href="https://oi-wiki.org/ds/dsu-complexity/">https://oi-wiki.org/ds/dsu-complexity/</a></p>
<h3 id="带权并查集"><a href="#带权并查集" class="headerlink" title="带权并查集"></a>带权并查集</h3><p>其实带权并查集和普通的并查集没有什么太大的不同,只是在我们每一次改变权值的时候都改一下到根节点的距离罢了<br>(其实我也不会,明天学会再改博客)</p>
<h3 id="可持久化并查集"><a href="#可持久化并查集" class="headerlink" title="可持久化并查集"></a>可持久化并查集</h3><p>(不会,以后再说。。。)<br>(这种东西应该是要在以后重新发博客的。。。如果你以后在我的博客之中翻到了。。。就不要让我回来改博客了。。。很累的。。。)</p>
<h3 id="经典题"><a href="#经典题" class="headerlink" title="经典题"></a>经典题</h3><p>NOI2015 程序自动分析<br>JSOI2008 星球大战<br>NOI2001 食物链<br>NOI2002 银河英雄传说<br>UVA11987 Almost Union-Find</p>
<h3 id="应用"><a href="#应用" class="headerlink" title="应用"></a>应用</h3><p>最小生成树(马上要去写)和 LCA 最近公共祖先(写完了,可以看)</p>
<h3 id="尾声"><a href="#尾声" class="headerlink" title="尾声"></a>尾声</h3><p>很大一部分借鉴了 OI WIKI<br>侵权勿喷。。。(我非盈利 aaa<br>good bye</p>
]]></content>
<tags>
<tag>图</tag>
</tags>
</entry>
<entry>
<title>P1827</title>
<url>/%E6%A0%91/</url>
<content><![CDATA[<h1 id="P1827-奶牛"><a href="#P1827-奶牛" class="headerlink" title="P1827 奶牛"></a>P1827 <strong>奶牛</strong></h1><h2 id="题目解读"><a href="#题目解读" class="headerlink" title="题目解读"></a><strong>题目解读</strong></h2><p>其实说到底就是一道树的后序遍历反推而已嘛<br>首先,让我们看一遍题目:<br>给了一棵树的前序中序遍历,让求出后序遍历;(习惯性的打出分号<br><a href="https://oi-wiki.org/graph/tree-basic/#_14%EF%BC%88%E9%99%84%E4%B8%8AOI-WIKI%E7%9A%84%E8%AE%B2%E8%A7%A3">https://oi-wiki.org/graph/tree-basic/#_14(附上OI-WIKI的讲解</a><br>首先我们知道前序遍历在开头是根节点,那么,就将根节点取出(用 string 可做到<br>那么,在中序遍历中找到根节点的位置,左边就是左子树,右边就是右子树<br>在左子树中,前序遍历的<strong>左半截</strong>的开头就是左子树的根节点,再将根节点取出,再在中序遍历的<strong>左半边</strong>寻找……<br>然后再在右子树中重新做一遍这个过程,<em>(注意)</em>重新做的时候也要从左子树开始做<br>!!!这是什么!!!<br>赤裸裸的递归啊<br>所以!就可以用一个递归小函数来解决这个问题</p>
<h2 id="另一件事情"><a href="#另一件事情" class="headerlink" title="** 另一件事情 **"></a>** 另一件事情 **</h2><p>在上述说明中呢,看上去非常的简单;<br>但是,上面提到了前序遍历的左半边,难道是说要在存一个 string 做吗;<br>是的,需要————<br>但是不要惊慌<br>接下来我要说的就是 string 的库函数之一:substr();<br>substr(本质上是复制字符串的一部分放入新的字符串之中;<br>就省得孩子们一遍遍的 for 了</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> N 10010</span></span><br><span class="line">string a,b;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dfs</span><span class="params">(string aa,string bb)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span>(aa.<span class="built_in">empty</span>())<span class="keyword">return</span>; <span class="comment">//这是在判断边界</span></span><br><span class="line"> <span class="keyword">char</span> root=aa[<span class="number">0</span>]; <span class="comment">//将前序遍历的根节点取出来</span></span><br><span class="line"> <span class="keyword">int</span> k=bb.<span class="built_in">find</span>(root); <span class="comment">//找到根节点</span></span><br><span class="line"> aa.<span class="built_in">erase</span>(aa.<span class="built_in">begin</span>()); <span class="comment">//将根节点从string中删除</span></span><br><span class="line"> string laa=aa.<span class="built_in">substr</span>(<span class="number">0</span>,k),raa=aa.<span class="built_in">substr</span>(k),lbb=bb.<span class="built_in">substr</span>(<span class="number">0</span>,k),rbb=bb.<span class="built_in">substr</span>(k+<span class="number">1</span>); <span class="comment">//激动人心的拆卸时间</span></span><br><span class="line"> <span class="built_in">dfs</span>(laa,lbb);<span class="built_in">dfs</span>(raa,rbb); <span class="comment">//遍历</span></span><br><span class="line"> cout<<root; <span class="comment">//由于是后序遍历所以最后输出根节点</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"> cin>>a>>b;</span><br><span class="line"> <span class="built_in">dfs</span>(b,a);</span><br><span class="line"> cout<<endl;</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>
<h2 id="尾声"><a href="#尾声" class="headerlink" title="尾声"></a><strong>尾声</strong></h2><p>森森的第一篇学术博客结束</p>
]]></content>
<tags>
<tag>图</tag>
</tags>
</entry>
<entry>
<title>树状数组</title>
<url>/%E6%A0%91%E7%8A%B6%E6%95%B0%E7%BB%84/</url>
<content><![CDATA[<h1 id="被迫营业,学习了树状数组"><a href="#被迫营业,学习了树状数组" class="headerlink" title="被迫营业,学习了树状数组"></a>被迫营业,学习了树状数组</h1><h1 id="树状数组"><a href="#树状数组" class="headerlink" title="树状数组"></a>树状数组</h1><h2 id="粗:"><a href="#粗:" class="headerlink" title="粗:"></a>粗:</h2><p>树状数组是一个基于二进制的数据结构,我们将每一个值存为区间右端点的一个“lowbit”长度的区间中,就构成了树状数组(真的是很粗。。。)</p>
<h2 id="细:简介"><a href="#细:简介" class="headerlink" title="细:简介"></a>细:简介</h2><p>首先,树状数组这个数据结构可以动态维护区间和,支持单点修改区间查询(其实还支持区间修改单点查询或者都一起支持,这个后续再讲,因为是扩展内容)</p>
<p>在学习快速幂算法的过程中,我们可以知道一个事实:</p>
<p>任意正整数都可以表示为 2 的整数次幂相加(也就是二进制分解)</p>
<p>那么,6=4+2(2^2+2^1),14=8+4+2(2^3+2^2+2^1)</p>
<p>那么我们可以将 1<del>6 这个区间表示为 1</del>4 并 5<del>6(具体为什么不是 1</del>2 并 3~6 一会再说)</p>
<p>1<del>14 可以表示为 1</del>8 并 9<del>12 并 13</del>14</p>
<p>我们就可以进行存储。</p>
<p>那么。。。如何存储或查询呢?</p>
<p>6 可以表示为(110)2,14 可以表示为(1110)2,我们可以通过一个小操作实现取出 110 最右边(最小的)那个 1,就是<strong>lowbit</strong>。</p>
<h2 id="lowbit-运算"><a href="#lowbit-运算" class="headerlink" title="lowbit 运算"></a>lowbit 运算</h2><p>lowbit 操作,涉及到了一些位运算的知识:</p>
<p>我们不妨设 n>0,n 的第 k 位是 1,0~k-1 位是 0(1000000……)</p>
<p>那么我们先将 n 取反,此时第 k 位变成了 0,0~k-1 都是 1</p>
<p>我们再将 n 加上 1,那么最后的那 k 位就变回了原来的样子</p>
<p>但是:第 k+1 位往后,就变成了与之前相反的数</p>
<p>我们可以想到按位 and 操作:只要有一个不是 0,就把这一位变成 0,都是 1 变成 1</p>
<p>k+1 位往后是都相反的,那说明那几位中按位 and 运算一定会全部变成 0</p>
<p>第 k 位从始至终都是 1,0~k-1 位从始至终都是 0</p>
<p>那么这个数只剩下了 2^k-1</p>
<p>表示为:n&(~n+1)</p>
<p>然而在补码的表示下,<del>n=-1-n,那么</del>n+1==-n</p>
<p>所以 lowbit 运算最后就变成了 n&-n</p>
<h2 id="查询和存储"><a href="#查询和存储" class="headerlink" title="查询和存储"></a>查询和存储</h2><h3 id="存储-或者说是单点修改"><a href="#存储-或者说是单点修改" class="headerlink" title="存储(或者说是单点修改)"></a>存储(或者说是单点修改)</h3><p>在讲完了 lowbit 操作之后,就到了实现</p>
<p>查询的时候,我们还是以 n 来举例子</p>
<p>我们想要存储 1-n 的前缀和,就是分步走</p>
<p>7 存到 t[7]之后</p>
<p>我们就需要修改它的父节点</p>
<p>通过 lowbit 操作我们可以知道,我们现在存储的节点的区间长度是 lowbit(n)</p>
<p>我们想要到我们的父节点,父节点的区间长度应是我们的二倍(或者是和之前的进行拼接成为更大的区间)</p>
<p>所以我们应该让 lowbit 变大。</p>
<p>由我们的计算机存储方式二进制可以得到,lowbit 的这一位加上 1,会变成 0,然而更高的哪一位会加一(直到不能进位)(两个同样长的挨着的区间分别存储是不优的,因为我们是在存储前缀和,直接详见可以得到答案就不需要浪费空间进行存储),这正好顺应了我们想要存区间的需求,那我们就让 n 加上 lowbit(n)便是他的父节点</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><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"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">for</span> (; x <= n; x += x & -x)</span><br><span class="line"> t[x] += y;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="查询"><a href="#查询" class="headerlink" title="查询"></a>查询</h3><p>存储其实和查询有一点反操作的感觉</p>
<p>我们考虑一个区间 1~7</p>
<p>7=(111)2</p>
<p>那么,我们就可以知道,sum(1~7)=sum(1-4)+sum(5-6)+sum(7);</p>
<p>我们进行 7 的存储,就可以分步走:</p>
<p>首先将 sum(7)存储进 sum(1-7),7-=1 现在为 6</p>
<p>将 sum(5-6)存进 sum(1-7),6-=2 现在为 4</p>
<p>再将 sum(1-4)存进 sum(1-7,4-=4 现在为 0,结束</p>
<p>所以我们 sum(n)存的区间的长度就可以是 lowbit(n)</p>
<p>那样的话 sum(n-lowbit(n))存的就是下一位(100000……)直到变成 0</p>
<p>这就是树状数组的存储</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">ask</span><span class="params">(<span class="keyword">int</span> x)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> ans = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (; x; x -= x & -x)</span><br><span class="line"> ans += t[x];</span><br><span class="line"> <span class="keyword">return</span> ans;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="例题"><a href="#例题" class="headerlink" title="例题"></a>例题</h2><p>洛谷 P3374,P3368 是模板题,可以去看看</p>
<h3 id="P1966-火柴排队-题目链接"><a href="#P1966-火柴排队-题目链接" class="headerlink" title="P1966 火柴排队 题目链接"></a>P1966 火柴排队 <a href="https://www.luogu.com.cn/problem/P1966">题目链接</a></h3><p>这道题倒是不难(我个人感觉应该到不了蓝色。。。)(我太菜了)</p>
<p>根据题目所说的是,两根火柴的距离定义为(a-b)^2,那么就让第 i 长的和第 i 长的放在一起,这样会是最小(贪心)</p>
<p>因为如果这样的话就相当于是火柴的对应关系固定的死死的,那么,我们就将火柴以编号命名(离散化但不完全离散化),然后求逆序对数</p>
<p>由于我们想让第 1 对应第 1,就相当于 a 数组 2 3 1 4,我将它变为 2->1,3->2,1->3,4->4,序列变为 1 2 3 4</p>
<p>然而 b 数组对应之后变成个 1 4 2 3,就相当于是冒泡排序求最少交换多少次,这个次数就是序列的逆序对数</p>
<p>(所以我说很简单嘛)</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> maxn 200010</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> mod 99999997</span></span><br><span class="line"><span class="keyword">int</span> n;</span><br><span class="line"><span class="keyword">int</span> a[maxn], b[maxn], c1[maxn], c2[maxn];</span><br><span class="line">map<<span class="keyword">int</span>, <span class="keyword">int</span>> q;</span><br><span class="line"><span class="keyword">int</span> t[maxn];</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"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">for</span> (; x <= n; x += x & -x)</span><br><span class="line"> t[x] += y;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">ask</span><span class="params">(<span class="keyword">int</span> x)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> ans = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (; x; x -= x & -x)</span><br><span class="line"> ans += t[x];</span><br><span class="line"> <span class="keyword">return</span> ans;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">signed</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"> ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line"> cin >> 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++)</span><br><span class="line"> cin >> a[i], c1[i] = a[i];</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"> cin >> b[i], c2[i] = b[i];</span><br><span class="line"> <span class="built_in">sort</span>(c1 + <span class="number">1</span>, c1 + <span class="number">1</span> + n);</span><br><span class="line"> <span class="built_in">sort</span>(c2 + <span class="number">1</span>, c2 + <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 <= n; i++)</span><br><span class="line"> {</span><br><span class="line"> a[i] = <span class="built_in">lower_bound</span>(c1 + <span class="number">1</span>, c1 + <span class="number">1</span> + n, a[i]) - c1;</span><br><span class="line"> b[i] = <span class="built_in">lower_bound</span>(c2 + <span class="number">1</span>, c2 + <span class="number">1</span> + n, b[i]) - c2;</span><br><span class="line"> q[b[i]] = i;</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><br><span class="line"> a[i] = q[a[i]];</span><br><span class="line"> <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><br><span class="line"> {</span><br><span class="line"> <span class="built_in">add</span>(a[i], <span class="number">1</span>);</span><br><span class="line"> ans += <span class="built_in">ask</span>(n) - <span class="built_in">ask</span>(a[i]);</span><br><span class="line"> }</span><br><span class="line"> cout << ans % mod << endl;</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>
<h3 id="P5677-配对统计-题目链接"><a href="#P5677-配对统计-题目链接" class="headerlink" title="P5677 配对统计 题目链接"></a>P5677 配对统计 <a href="https://www.luogu.com.cn/problem/P5677">题目链接</a></h3><p>这道题,其实也不难,但是我想了很长时间</p>
<p>(其实就是理解错题意了。。。)</p>
<p>我们考虑首先对于好的配对进行预处理,求出每一组好的配对</p>
<p>然后进行记录。记录的过程中,我们可以将配对放在一个数组中。</p>
<p>配对分几种情况:</p>
<p>首先,如果说我们将序列上的所有数字放在一条数轴上,一个数字对应的好的配对一定在它的两侧,那么分三种情况:</p>
<p>左边距离小,右边距离小,两边一样</p>
<p>就可以进行处理。两边一样的就有两组好的配对是当前数字的。</p>
<p>我们处理完配对之后,将它们在存储时改为左端点右端点单增(我只需要统计个数又不统计在哪)</p>
<p>我们对配对排序(以右端点升序排序),再将询问进行升序排序(同样是右端点)</p>
<p>我们枚举每一个询问,将右端点比询问的右端点小的配对的左端点放入树状数组(很绕口—)</p>
<p>我们统计左端点在 l<del>r 区间之内的个数,就是配对在 l</del>r 区间的个数(右端点比询问的右端点小,比自己的左端点大,所以只要我的左端点大于询问的左端点就可以是一个配对了)</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> maxn 600010</span></span><br><span class="line"><span class="keyword">int</span> n, m, t[maxn];</span><br><span class="line">pair<<span class="keyword">int</span>, <span class="keyword">int</span>> q[maxn];</span><br><span class="line"><span class="keyword">int</span> cnt;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">no</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"> <span class="keyword">int</span> q1, q2, pos;</span><br><span class="line">} question[maxn];</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">qcmp</span><span class="params">(no x, no y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (x.q2 == y.q2)</span><br><span class="line"> <span class="keyword">return</span> x.q1 < y.q1;</span><br><span class="line"> <span class="keyword">return</span> x.q2 < y.q2;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> ans;</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> pos)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">while</span> (pos <= n)</span><br><span class="line"> t[pos]++, pos += (pos & -pos);</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">ask</span><span class="params">(<span class="keyword">int</span> num)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> sum = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> (num > <span class="number">0</span>)</span><br><span class="line"> sum += t[num], num -= (num & -num);</span><br><span class="line"> <span class="keyword">return</span> sum;</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="class">{</span></span><br><span class="line"> <span class="keyword">int</span> num, pos;</span><br><span class="line">} a[maxn];</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">cmp</span><span class="params">(node x, node y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> x.num < y.num;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">addq</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> q[++cnt].first = <span class="built_in">min</span>(x, y);</span><br><span class="line"> q[cnt].second = <span class="built_in">max</span>(x, y);</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">comp</span><span class="params">(pair<<span class="keyword">int</span>, <span class="keyword">int</span>> x, pair<<span class="keyword">int</span>, <span class="keyword">int</span>> y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (x.second == y.second)</span><br><span class="line"> <span class="keyword">return</span> x.first < y.first;</span><br><span class="line"> <span class="keyword">return</span> x.second < y.second;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">signed</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"> ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line"> cin >> n >> m;</span><br><span class="line"> <span class="keyword">if</span>(n==<span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> cout<<<span class="number">0</span><<endl;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= n; i++)</span><br><span class="line"> cin >> a[i].num, a[i].pos = i;</span><br><span class="line"> <span class="built_in">sort</span>(a + <span class="number">1</span>, a + <span class="number">1</span> + n, cmp);</span><br><span class="line"> <span class="built_in">addq</span>(a[<span class="number">1</span>].pos, a[<span class="number">2</span>].pos);</span><br><span class="line"> <span class="built_in">addq</span>(a[n].pos, a[n - <span class="number">1</span>].pos);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">2</span>; i < n; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (a[i].num - a[i - <span class="number">1</span>].num < a[i + <span class="number">1</span>].num - a[i].num)</span><br><span class="line"> <span class="built_in">addq</span>(a[i].pos, a[i - <span class="number">1</span>].pos);</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (a[i].num - a[i - <span class="number">1</span>].num == a[i + <span class="number">1</span>].num - a[i].num)</span><br><span class="line"> <span class="built_in">addq</span>(a[i].pos, a[i - <span class="number">1</span>].pos), <span class="built_in">addq</span>(a[i].pos, a[i + <span class="number">1</span>].pos);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">addq</span>(a[i].pos, a[i + <span class="number">1</span>].pos);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">sort</span>(q + <span class="number">1</span>, q + <span class="number">1</span> + cnt, comp);</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><br><span class="line"> cin >> question[i].q1 >> question[i].q2, question[i].pos = i;</span><br><span class="line"> <span class="built_in">sort</span>(question + <span class="number">1</span>, question + <span class="number">1</span> + m, qcmp);</span><br><span class="line"> <span class="keyword">int</span> j = <span class="number">1</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><br><span class="line"> {</span><br><span class="line"> <span class="keyword">while</span> (q[j].second <= question[i].q2 && j <= cnt)</span><br><span class="line"> <span class="built_in">add</span>(q[j].first),j++;</span><br><span class="line"> ans += (<span class="keyword">long</span> <span class="keyword">long</span>)(j - <span class="number">1</span> - <span class="built_in">ask</span>(question[i].q1 - <span class="number">1</span>)) * question[i].pos;</span><br><span class="line"> }</span><br><span class="line"> cout << ans << endl;</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>
<h1 id="树状数组结束-完结撒花"><a href="#树状数组结束-完结撒花" class="headerlink" title="树状数组结束 完结撒花"></a>树状数组结束 完结撒花</h1>]]></content>
<tags>
<tag>数据结构</tag>
</tags>
</entry>
<entry>
<title>线性动态规划做题笔记</title>
<url>/%E7%BA%BF%E6%80%A7%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%E5%81%9A%E9%A2%98%E7%AC%94%E8%AE%B0/</url>
<content><![CDATA[<h1 id="动态更新中"><a href="#动态更新中" class="headerlink" title="动态更新中"></a>动态更新中</h1><h1 id="P1541-乌龟棋"><a href="#P1541-乌龟棋" class="headerlink" title="P1541 乌龟棋"></a>P1541 乌龟棋</h1><p><a href="https://www.luogu.com.cn/problem/P1541">题目链接</a></p>
<p>这个题虽然是个绿的,但是还有总结一下的价值的</p>
<p>首先我们可以想到一个非常显然的做法就是:每一种卡片我都记录到状态里面,然后记录一下当前位置</p>
<p>这样时间空间复杂度都会炸</p>
<p>那么就可以很显然的发现。。。位置减去三种卡片对应的走过的位置就可以推出用第四种卡片走的距离或者说用了几张第四种卡片</p>
<p>然后就可以省掉一维</p>
<p>(有的地方会有一点点的细节。。。不过也没有大碍</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">400</span>;</span><br><span class="line"><span class="keyword">int</span> f[<span class="number">360</span>][<span class="number">41</span>][<span class="number">41</span>][<span class="number">41</span>];</span><br><span class="line"><span class="keyword">int</span> n, m;</span><br><span class="line"><span class="keyword">int</span> cnt[<span class="number">5</span>];</span><br><span class="line"><span class="keyword">int</span> v[maxn];</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">check</span><span class="params">(<span class="keyword">int</span> i, <span class="keyword">int</span> j, <span class="keyword">int</span> k, <span class="keyword">int</span> l)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (cnt[<span class="number">4</span>] * <span class="number">4</span> + j + k * <span class="number">2</span> + l * <span class="number">3</span> < i - <span class="number">1</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;<span class="comment">//如果四种卡片走的位置总和不够。。。</span></span><br><span class="line"> <span class="keyword">if</span> (((i - <span class="number">1</span>) - j - k * <span class="number">2</span> - l * <span class="number">3</span>) % <span class="number">4</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;<span class="comment">//如果给第四种卡片留下来的距离并不能整除</span></span><br><span class="line"> <span class="keyword">if</span> (i - <span class="number">1</span> < j + k * <span class="number">2</span> + l * <span class="number">3</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;<span class="comment">//如果三种卡片已经超过了距离</span></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> <span class="comment">//ps:不知道全不全但是至少能过</span></span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">signed</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="meta">#<span class="meta-keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"in.txt"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"out.txt"</span>, <span class="string">"w"</span>, stdout);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</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 >> n >> m;</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"> cin >> v[i];</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><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> op;</span><br><span class="line"> cin >> op;</span><br><span class="line"> cnt[op]++;</span><br><span class="line"> }</span><br><span class="line"> f[<span class="number">1</span>][<span class="number">0</span>][<span class="number">0</span>][<span class="number">0</span>] = v[<span class="number">1</span>];<span class="comment">//初始化(dp的初始化部分还是很重要的</span></span><br><span class="line"> <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">2</span>; i <= n; i++)(在第一个位置上只有一种可能我们就不算他了</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">0</span>; j <= cnt[<span class="number">1</span>]; j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k = <span class="number">0</span>; k <= cnt[<span class="number">2</span>]; k++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> l = <span class="number">0</span>; l <= cnt[<span class="number">3</span>]; l++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">check</span>(i, j, k, l))<span class="comment">//判断是否合法(就是能不能用这几张卡片走到这个位置</span></span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">if</span> (j)</span><br><span class="line"> f[i][j][k][l] = <span class="built_in">max</span>(f[i][j][k][l], f[i - <span class="number">1</span>][j - <span class="number">1</span>][k][l]);</span><br><span class="line"> <span class="keyword">if</span> (k)</span><br><span class="line"> f[i][j][k][l] = <span class="built_in">max</span>(f[i][j][k][l], f[i - <span class="number">2</span>][j][k - <span class="number">1</span>][l]);</span><br><span class="line"> <span class="keyword">if</span> (l)</span><br><span class="line"> f[i][j][k][l] = <span class="built_in">max</span>(f[i][j][k][l], f[i - <span class="number">3</span>][j][k][l - <span class="number">1</span>]);</span><br><span class="line"> <span class="keyword">if</span> (i - <span class="number">1</span> - j - k * <span class="number">2</span> - l * <span class="number">3</span>)</span><br><span class="line"> f[i][j][k][l] = <span class="built_in">max</span>(f[i][j][k][l], f[i - <span class="number">4</span>][j][k][l]);</span><br><span class="line"> f[i][j][k][l] += v[i];</span><br><span class="line"> ans = <span class="built_in">max</span>(f[i][j][k][l], ans);</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"> cout << ans << endl;</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>
<p>初始化还是比较重要的(下面那道题题我就是抄的题解的初始化</p>
<h1 id="SP703-SERVICE-Mobile-Service"><a href="#SP703-SERVICE-Mobile-Service" class="headerlink" title="SP703 SERVICE - Mobile Service"></a>SP703 SERVICE - Mobile Service</h1><p> <a href="https://www.luogu.com.cn/problem/SP703">题目链接</a></p>
<p>这个题和上面那个题还是有着异曲同工之妙的</p>
<p>但是比上面那个题难一点。。。</p>
<p>首先朴素的dp方法:把所有的状态存进去</p>
<p>就是1000个申请,200个a的位置,200个b的位置,200个c的位置</p>
<p>会炸。。。</p>
<p>那么就开始分析题目性质:</p>
<p>我们会发现:在第i个申请结束之后是一定会有一个人的位置在p[i]的(重要</p>
<p>那么我们可以压缩掉一维空间(还有时间</p>
<p>设$f[i][x][y]$为第i个申请,一个人在x,一个人在y,一个人在p[i]的方案数</p>
<p>那么……就可以转移:</p>
<p>$$f[i + 1][j][k] = min(f[i + 1][j][k], f[i][j][k] + w[p[i]][p[i + 1]]);$$$$<br>f[i + 1][p[i]][k] = min(f[i + 1][p[i]][k], f[i][j][k] + w[j][p[i + 1]]);$$$$<br>f[i + 1][j][p[i]] = min(f[i + 1][j][p[i]], f[i][j][k] + w[k][p[i + 1]]);$$</p>
<p>然后就是初始化的事情了:(我写博客还是要把初始化写上的</p>
<p>$f[0][1][2]$是初始状态,设为0,其他都设成inf,由于我们有个p数组的限制,那么我们就可以把p[0]改一下,p[0]改为3</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">1010</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxm = <span class="number">210</span>;</span><br><span class="line"><span class="keyword">int</span> f[maxn][maxm][maxm];</span><br><span class="line"><span class="keyword">int</span> p[maxn];</span><br><span class="line"><span class="keyword">int</span> t, l, n;</span><br><span class="line"><span class="keyword">int</span> w[maxm][maxm];</span><br><span class="line"><span class="function"><span class="keyword">signed</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="meta">#<span class="meta-keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"in.txt"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"out.txt"</span>, <span class="string">"w"</span>, stdout);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</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 >> t;</span><br><span class="line"> <span class="keyword">while</span> (t--)</span><br><span class="line"> {</span><br><span class="line"> cin >> l >> n;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= l; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">1</span>; j <= l; j++)</span><br><span class="line"> {</span><br><span class="line"> cin >> w[i][j];</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><br><span class="line"> cin >> p[i];</span><br><span class="line"> <span class="built_in">memset</span>(f, <span class="number">0x3f</span>, <span class="built_in"><span class="keyword">sizeof</span></span>(f));</span><br><span class="line"> f[<span class="number">0</span>][<span class="number">1</span>][<span class="number">2</span>] = <span class="number">0</span>;</span><br><span class="line"> p[<span class="number">0</span>] = <span class="number">3</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><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">1</span>; j <= l; j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k = <span class="number">1</span>; k <= l; k++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (p[i] == j || p[i] == k || j == k)</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> f[i + <span class="number">1</span>][j][k] = <span class="built_in">min</span>(f[i + <span class="number">1</span>][j][k], f[i][j][k] + w[p[i]][p[i + <span class="number">1</span>]]);</span><br><span class="line"> f[i + <span class="number">1</span>][p[i]][k] = <span class="built_in">min</span>(f[i + <span class="number">1</span>][p[i]][k], f[i][j][k] + w[j][p[i + <span class="number">1</span>]]);</span><br><span class="line"> f[i + <span class="number">1</span>][j][p[i]] = <span class="built_in">min</span>(f[i + <span class="number">1</span>][j][p[i]], f[i][j][k] + w[k][p[i + <span class="number">1</span>]]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">int</span> ans = <span class="number">0x3f3f3f3f3f3f3f3f</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= l; i++)</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">1</span>; j <= l; j++)</span><br><span class="line"> ans = <span class="built_in">min</span>(ans, f[n][i][j]);</span><br><span class="line"> cout << ans << endl;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h1 id="SP15637-GNYR04H-Mr-Youngs-Picture-Permutations"><a href="#SP15637-GNYR04H-Mr-Youngs-Picture-Permutations" class="headerlink" title="SP15637 GNYR04H - Mr Youngs Picture Permutations"></a>SP15637 GNYR04H - Mr Youngs Picture Permutations</h1><p>好题!(但是机房里基本没人做这个题是什么鬼啊</p>
<p>这个题猛然一看完全没有思路叭……</p>
<p>但是我们考虑dp的时候……如果我们需要满足题目中的限制的话,改变一下dp的方式:</p>
<p>我们考虑向序列中插数,从小往大插</p>
<p>那么就会有一个性质:从小往大插就说明当前插得数一定是最大的</p>
<p>那么就说明:一定满足条件!</p>
<p>那么我们考虑插数的前提条件是什么:</p>
<p>我们可以往一个位置上面插数,手下我们要保证上一行的当前列是有数的(这个数一定比当前数小)(并且第一行随便插</p>
<p>如果上一行的这一列没有数,后面一定会插进来一个数,那个数肯定比当前数大,就会不符合题意</p>
<p>并且我们还要保证这一行没有插满</p>
<p>那么我们设dp状态:由于最多只有5行,所以我们就设dp函数$f[i][j][k][l][p]$表示第几行站着多少人</p>
<p>然后转移就可以了</p>
<p>初始化的话:$f[0][0][0][0][0]=1$就没了</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">33</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> f[maxn][maxn][maxn][maxn][maxn];</span><br><span class="line"><span class="keyword">int</span> n, a[<span class="number">10</span>];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">signed</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="meta">#<span class="meta-keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"in.txt"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"out,txt"</span>, <span class="string">"w"</span>, stdout);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</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"> <span class="keyword">while</span> (cin >> n && n)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">memset</span>(f, <span class="number">0</span>, <span class="built_in"><span class="keyword">sizeof</span></span>(f));</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= <span class="number">5</span>; i++)</span><br><span class="line"> a[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 <= n; i++)</span><br><span class="line"> cin >> a[i];</span><br><span class="line"> f[<span class="number">0</span>][<span class="number">0</span>][<span class="number">0</span>][<span class="number">0</span>][<span class="number">0</span>] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i <= a[<span class="number">1</span>]; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">0</span>; j <= i; j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k = <span class="number">0</span>; k <= j; k++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> l = <span class="number">0</span>; l <= k; l++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> p = <span class="number">0</span>; p <= l; p++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (i < a[<span class="number">1</span>])</span><br><span class="line"> f[i + <span class="number">1</span>][j][k][l][p] += f[i][j][k][l][p];</span><br><span class="line"> <span class="keyword">if</span> (j < a[<span class="number">2</span>] && i > j)</span><br><span class="line"> f[i][j + <span class="number">1</span>][k][l][p] += f[i][j][k][l][p];</span><br><span class="line"> <span class="keyword">if</span> (k < a[<span class="number">3</span>] && j > k)</span><br><span class="line"> f[i][j][k + <span class="number">1</span>][l][p] += f[i][j][k][l][p];</span><br><span class="line"> <span class="keyword">if</span> (l < a[<span class="number">4</span>] && k > l)</span><br><span class="line"> f[i][j][k][l + <span class="number">1</span>][p] += f[i][j][k][l][p];</span><br><span class="line"> <span class="keyword">if</span> (p < a[<span class="number">5</span>] && l > p)</span><br><span class="line"> f[i][j][k][l][p + <span class="number">1</span>] += f[i][j][k][l][p];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> cout << f[a[<span class="number">1</span>]][a[<span class="number">2</span>]][a[<span class="number">3</span>]][a[<span class="number">4</span>]][a[<span class="number">5</span>]] << endl;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h1 id="P2943-USACO09MAR-Cleaning-Up-G"><a href="#P2943-USACO09MAR-Cleaning-Up-G" class="headerlink" title="P2943 [USACO09MAR]Cleaning Up G"></a>P2943 [USACO09MAR]Cleaning Up G</h1><p><a href="https://www.luogu.com.cn/problem/P2943">题目链接</a></p>
<p>这个题是真的好…</p>
<p>首先我考虑一件事情(大大缩短时间的事情:</p>
<p>一段连续的区间我们最多只会给他根号n个机会(根号n个不同的数字</p>
<p>因为如果我们把n个数字都变成自己一个人一次吃饭的话答案应该是n,所以答案绝对小于等于n</p>
<p>那么我们设pre[i]表示上一个与在i位置的食物相同的食物位置,</p>
<p>nex[i]表示下一个,</p>
<p>last[i]表示种类为i的食物出现的最后一个位置,</p>
<p>如果i点没有上一个则pre[i]=0,没有下一个则nex[i]=n+1,</p>
<p>然后进行求解:</p>
<p>判断时,如果pre[i]<pos[j],说明i这个点在[pos[j],i-1]中并没有出现过,</p>
<p>设cnt[j]为pos[j]对应的出现次数,则cnt[j]++;</p>
<p>当cnt[j]>j时,显然pos[j]应该右移,如果nex[pos[j]]<i,说明在pos[j]这个位置的食物在区间中出现了不止一次,</p>
<p>则删除它后不同个数仍然不变,因此要不断右移,直到nex[pos[j]]>=i,此时删除它后不同个数减一</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">40010</span>;</span><br><span class="line"><span class="keyword">int</span> n, m;</span><br><span class="line"><span class="keyword">int</span> a[maxn];</span><br><span class="line"><span class="keyword">int</span> pre[maxn], nex[maxn], lst[maxn];</span><br><span class="line"><span class="keyword">int</span> f[maxn], pos[maxn];</span><br><span class="line"><span class="keyword">int</span> cnt[maxn];</span><br><span class="line"><span class="comment">/*设pre[i]表示上一个与在i位置的食物相同的食物位置,</span></span><br><span class="line"><span class="comment">nex[i]表示下一个,</span></span><br><span class="line"><span class="comment">last[i]表示种类为i的食物出现的最后一个位置,</span></span><br><span class="line"><span class="comment">如果i点没有上一个则pre[i]=0,没有下一个则nex[i]=n+1,</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">signed</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="meta">#<span class="meta-keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"in.txt"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"out.txt"</span>, <span class="string">"w"</span>, stdout);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</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 >> n >> m;</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><br><span class="line"> cin >> a[i];</span><br><span class="line"> pre[i] = lst[a[i]];</span><br><span class="line"> nex[lst[a[i]]] = i;</span><br><span class="line"> lst[a[i]] = i;</span><br><span class="line"> f[i] = <span class="number">1e9</span>;</span><br><span class="line"> nex[i] = n + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">int</span> t = <span class="built_in">sqrt</span>(n);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= t; i++)</span><br><span class="line"> pos[i] = <span class="number">1</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><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">1</span>; j <= t; j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (pre[i] < pos[j])</span><br><span class="line"> cnt[j]++;<span class="comment">//新加入的点我就观察一下,如果说没有出现过就说明需要更新现在区间里面有多少个不同的类别</span></span><br><span class="line"> <span class="keyword">if</span> (cnt[j] > j)</span><br><span class="line"> {</span><br><span class="line"> <span class="comment">//如果当前的区间里面不同的类别数量超过了就应该更改</span></span><br><span class="line"> cnt[j]--;</span><br><span class="line"> <span class="comment">//既然超过了那就让他减少(因为我们反正后面都要让它变成不重复的还不如现在就把他干掉)</span></span><br><span class="line"> <span class="keyword">while</span> (nex[pos[j]] < i)</span><br><span class="line"> pos[j]++;<span class="comment">//如果说当前数字在后面出现过就删掉他</span></span><br><span class="line"> pos[j]++;<span class="comment">//一直删到最后一个,最后就不可以删了</span></span><br><span class="line"> }</span><br><span class="line"> f[i] = <span class="built_in">min</span>(f[i], f[pos[j] - <span class="number">1</span>] + j * j);<span class="comment">//更新</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> cout << f[n] << endl;</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>线段树</title>
<url>/%E7%BA%BF%E6%AE%B5%E6%A0%91/</url>
<content><![CDATA[<h1 id="一个可以累死人的数据结构"><a href="#一个可以累死人的数据结构" class="headerlink" title="一个可以累死人的数据结构"></a>一个可以累死人的数据结构</h1><h1 id="线段树(仅限于基础的那个)(zx-树这种的以后再说)"><a href="#线段树(仅限于基础的那个)(zx-树这种的以后再说)" class="headerlink" title="线段树(仅限于基础的那个)(zx 树这种的以后再说)"></a>线段树(仅限于基础的那个)(zx 树这种的以后再说)</h1><p>线段树是一个神奇的数据结构,他基本上什么区间操作都可以优化</p>
<p>这里讲一些基本的操作:单点修改,区间查询,区间修改(延迟标记)</p>
<h2 id="首先讲……概念…-我的线段树写的有的不一样,有的是用结构体存的左右节点,有的是在函数定义上存的节点"><a href="#首先讲……概念…-我的线段树写的有的不一样,有的是用结构体存的左右节点,有的是在函数定义上存的节点" class="headerlink" title="首先讲……概念…(我的线段树写的有的不一样,有的是用结构体存的左右节点,有的是在函数定义上存的节点)"></a>首先讲……概念…(我的线段树写的有的不一样,有的是用结构体存的左右节点,有的是在函数定义上存的节点)</h2><p>线段树,顾名思义,一个树形结构,存储的每一个节点都是一个线段</p>
<p>线段树的根节点存储着区间 1-n 的总信息,2 号存 1-(1+n)/2。。。</p>
<p>每一个线段的子节点都是自己线段的两半,直到叶子结点 l==r</p>
<h2 id="单点修改:"><a href="#单点修改:" class="headerlink" title="单点修改:"></a>单点修改:</h2><p>我们在进行单点修改的过程中,一般指令都是这个样子:c x y,表示操作 a[x]=y;</p>
<p>我们可以知道,线段树维护的是一条线段,只有叶子结点维护的是点,那么,我们首先应该递归到叶子结点,然后修改值,再向上修改父节点,就以区间和为例:</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">change</span><span class="params">(<span class="keyword">int</span> p,<span class="keyword">int</span> l,<span class="keyword">int</span> r,<span class="keyword">int</span> x,<span class="keyword">int</span> y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span>(l==r&&l==x)</span><br><span class="line"> {</span><br><span class="line"> t[p]=y;</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</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">if</span>(x<=mid)<span class="built_in">change</span>(p*<span class="number">2</span>,l,mid,x,y);</span><br><span class="line"> <span class="keyword">else</span> <span class="built_in">change</span>(p*<span class="number">2</span>+<span class="number">1</span>,mid+<span class="number">1</span>,r,x,y);</span><br><span class="line"> t[p]=t[p*<span class="number">2</span>]+t[p*<span class="number">2</span>+<span class="number">1</span>];</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="区间查询"><a href="#区间查询" class="headerlink" title="区间查询"></a>区间查询</h2><p>我们查询一个区间的时候,绝对不可能只是查询一个节点,基本上每一次都会查询到多个节点,那么我们应该怎么实现呢</p>
<p>操作 1:首先一个区间 l-r,我们可能需要查询的区间为 x1-x2,x2-x3,x3-x4</p>
<p>首先,如果我们递归到了当前的节点,这个节点的线段是被我们查询的这个区间所覆盖住的,我们直接把这个节点统计到答案之中,应为我们可以分成若干个线段树的节点,所以只要我们一直递归,就一定可以地轨道两个节点,l-x5,x6-r,这之间的所有节点都是被我们操作 1 所统计的,所以直接把这个答案返回。</p>
<p>如果不懂可以自己手模一遍</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">long</span> <span class="keyword">long</span> <span class="title">ask</span><span class="params">(<span class="keyword">int</span> p,<span class="keyword">int</span> l,<span class="keyword">int</span> r,<span class="keyword">int</span> x,<span class="keyword">int</span> y)</span></span>{</span><br><span class="line"> <span class="keyword">if</span>(x<=l && y>=r) <span class="keyword">return</span> t[p];</span><br><span class="line"> <span class="built_in">spread</span>(p);</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">long</span> <span class="keyword">long</span> ans=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">if</span>(x<=mid) ans+=<span class="built_in">ask</span>(p*<span class="number">2</span>,x,y);</span><br><span class="line"> <span class="keyword">if</span>(y>mid) ans+=<span class="built_in">ask</span>(p*<span class="number">2</span>+<span class="number">1</span>,x,y);</span><br><span class="line"> <span class="keyword">return</span> ans;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="区间修改(懒标记-laztag)"><a href="#区间修改(懒标记-laztag)" class="headerlink" title="区间修改(懒标记 laztag)"></a>区间修改(懒标记 laztag)</h2><p>这是一大难点啊。。。</p>
<p>首先对于我们上面的区间查询,我们可以感受到,线段树在对我们的区间进行一定的操作时,是可以划分为不同的节点进行操作的,那么,区间修改是否也可以这么做呢?</p>
<p>答案是肯定的</p>
<p>区间修改,在又一次经过操作 1 之后,我们就可以改变已经被覆盖的区间,比如区间和,我们就直接让这个区间增加 x*len(长度),然后 return</p>
<p>可是这样并不满足我们的需要,因为区间修改的时候这样修改的确会直接将上面的数据进行修改,但是,我们如果多次操作,修改的次数一多,查询有交集的区间就会受影响,因此,我们引入懒标记:</p>
<p>懒标记是标记我们当前的节点需要进行区间修改,还是区间和为例,我们 laz[x]就代表着 x 节点的线段中每一个数都需要增加 laz[x]这么多,只要我们每一次在进行区间统计师,都将我们的父节点的 laztag 传下来,我们就知道,从最开始到现在,我们没、每一个节点总共需要至少增加多少(我说至少是因为当前节点的子节点(或者是子孙节点)可能 laztag 非零)</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">spread</span><span class="params">(<span class="keyword">int</span> p)</span></span>{</span><br><span class="line"> <span class="keyword">if</span>(t[p].add){</span><br><span class="line"> t[p*<span class="number">2</span>].pre+=t[p].add*(t[p*<span class="number">2</span>].r-t[p*<span class="number">2</span>].l+<span class="number">1</span>);</span><br><span class="line"> t[p*<span class="number">2</span>+<span class="number">1</span>].pre+=t[p].add*(t[p*<span class="number">2</span>+<span class="number">1</span>].r-t[p*<span class="number">2</span>+<span class="number">1</span>].l+<span class="number">1</span>);</span><br><span class="line"> t[p*<span class="number">2</span>].add+=t[p].add;</span><br><span class="line"> t[p*<span class="number">2</span>+<span class="number">1</span>].add+=t[p].add;</span><br><span class="line"> t[p].add=<span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">change</span><span class="params">(<span class="keyword">int</span> p,<span class="keyword">int</span> x,<span class="keyword">int</span> y,<span class="keyword">int</span> z)</span></span>{</span><br><span class="line"> <span class="keyword">if</span>(x<=t[p].l && y>=t[p].r){</span><br><span class="line"> t[p].pre+=(<span class="keyword">long</span> <span class="keyword">long</span>)z*(t[p].r-t[p].l+<span class="number">1</span>);</span><br><span class="line"> t[p].add+=z;</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">spread</span>(p);</span><br><span class="line"> <span class="keyword">int</span> mid=t[p].l+t[p].r>><span class="number">1</span>;</span><br><span class="line"> <span class="keyword">if</span>(x<=mid) <span class="built_in">change</span>(p*<span class="number">2</span>,x,y,z);</span><br><span class="line"> <span class="keyword">if</span>(y>mid) <span class="built_in">change</span>(p*<span class="number">2</span>+<span class="number">1</span>,x,y,z);</span><br><span class="line"> t[p].pre=t[p*<span class="number">2</span>].pre+t[p*<span class="number">2</span>+<span class="number">1</span>].pre;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="例题"><a href="#例题" class="headerlink" title="例题"></a>例题</h2><p>这玩意的例题可多可难。。。这几个题我都至少调了有 2hours</p>
<h3 id="P2471-降雨量-题目链接"><a href="#P2471-降雨量-题目链接" class="headerlink" title="P2471 降雨量 题目链接"></a>P2471 降雨量 <a href="https://www.luogu.com.cn/problem/P2471">题目链接</a></h3><p>这道题真的不错(难调)</p>
<p>首先这道题需要进行分类讨论:</p>
<p>对于我们查询的区间(l,r)</p>
<p>我们先判断 false: 1.左端点年份确定了,右端点年份不确定,那我们的中间的最大值大于左端点(我们的定义应该是左端点的降雨量比右端点大并且右端点比一整个区间之内别的都大,所以中间最大值大于左端点就不成立) 2.右端点年份确定,左端点不确定,那么中间的最大值大于右端点,同样不成立 3.都确定了,左端点小于右端点</p>
<p>然后是 maybe: 1.年份不连续:右端点减去左端点和左右端点年分之差不相等 2.左端点不确定 3.右端点不确定</p>
<p>(由于我们已经切掉了 false 的情况,所以只剩下了 maybe 和 true,而有任何一个不确定都不可能是 true,所以。。。直接扔掉)</p>
<p>只要不是 FALSE 或者是 maybe 那就是 true</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> maxn 400010</span></span><br><span class="line"><span class="keyword">int</span> t[maxn];</span><br><span class="line"><span class="keyword">int</span> c[maxn];</span><br><span class="line"><span class="keyword">int</span> n, m;</span><br><span class="line"><span class="keyword">int</span> a[maxn], b[maxn];</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">build</span><span class="params">(<span class="keyword">int</span> rt, <span class="keyword">int</span> l, <span class="keyword">int</span> r)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (l == r)</span><br><span class="line"> {</span><br><span class="line"> t[rt] = b[l];</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</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="built_in">build</span>(rt * <span class="number">2</span>, l, mid);</span><br><span class="line"> <span class="built_in">build</span>(rt * <span class="number">2</span> + <span class="number">1</span>, mid + <span class="number">1</span>, r);</span><br><span class="line"> <span class="keyword">if</span> (a[mid + <span class="number">1</span>] - a[mid] > <span class="number">1</span> || c[rt * <span class="number">2</span>] || c[rt * <span class="number">2</span> + <span class="number">1</span>])</span><br><span class="line"> c[rt] = <span class="number">1</span>;</span><br><span class="line"> t[rt] = <span class="built_in">max</span>(t[rt * <span class="number">2</span>], t[rt * <span class="number">2</span> + <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">ask</span><span class="params">(<span class="keyword">int</span> rt, <span class="keyword">int</span> l, <span class="keyword">int</span> r, <span class="keyword">int</span> x, <span class="keyword">int</span> y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (x <= l && y >= r)</span><br><span class="line"> <span class="keyword">return</span> t[rt];</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> ans = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">if</span> (x <= mid)</span><br><span class="line"> ans = <span class="built_in">max</span>(ans, <span class="built_in">ask</span>(rt * <span class="number">2</span>, l, mid, x, y));</span><br><span class="line"> <span class="keyword">if</span> (y > mid)</span><br><span class="line"> ans = <span class="built_in">max</span>(ans, <span class="built_in">ask</span>(rt * <span class="number">2</span> + <span class="number">1</span>, mid + <span class="number">1</span>, r, x, y));</span><br><span class="line"> <span class="keyword">return</span> ans;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">signed</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"> cin >> 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++)</span><br><span class="line"> cin >> a[i] >> b[i];</span><br><span class="line"> <span class="built_in">build</span>(<span class="number">1</span>, <span class="number">1</span>, n);</span><br><span class="line"> cin >> m;</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><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> xx, yy;</span><br><span class="line"> cin >> xx >> yy;</span><br><span class="line"> <span class="keyword">if</span> (xx >= yy)</span><br><span class="line"> {</span><br><span class="line"> cout << <span class="string">"false"</span> << endl;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">int</span> x = <span class="built_in">lower_bound</span>(a + <span class="number">1</span>, a + <span class="number">1</span> + n, xx) - a;</span><br><span class="line"> <span class="keyword">int</span> y = <span class="built_in">lower_bound</span>(a + <span class="number">1</span>, a + <span class="number">1</span> + n, yy) - a;</span><br><span class="line"> <span class="keyword">int</span> mm =<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">if</span>(a[x]!=xx)x--;</span><br><span class="line"> <span class="keyword">if</span>(x+<span class="number">1</span><=y<span class="number">-1</span>)mm= <span class="built_in">ask</span>(<span class="number">1</span>, <span class="number">1</span>, n, x + <span class="number">1</span>, y - <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">if</span> ((a[y]==yy&&mm>=b[y])||(a[x]==xx&&mm>=b[x])||(a[y]==yy&&a[x]==xx&&b[x]<b[y]))</span><br><span class="line"> cout << <span class="string">"false"</span> << endl;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (y - x != a[y] - a[x] || a[x] != xx || a[y] != yy)</span><br><span class="line"> cout << <span class="string">"maybe"</span> << endl;</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> cout << <span class="string">"true"</span> << endl;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="P5490-扫描线(也是-lyd-例题)题目链接"><a href="#P5490-扫描线(也是-lyd-例题)题目链接" class="headerlink" title="P5490 扫描线(也是 lyd 例题)题目链接"></a>P5490 扫描线(也是 lyd 例题)<a href="https://www.luogu.com.cn/problem/P5490">题目链接</a></h3><p>扫描线是一个非常经典的算法,可以用来求面积和,周长并等</p>
<p>以面积和为例:</p>
<p>我们放进坐标系中几个矩形,我们想要求出它们的面积和,第一可以想到用容斥原理,但他很慢。。。</p>
<p>我们考虑这么一件事情,我们假设有一条平行于纵轴的直线,他在随便移动。</p>
<p>对于我们矩形放在一起之后的形状,我们可以把这个图形分割成很多个小的没有交集的矩形</p>
<p>所以,我们可以把这条线进行左右移动,每次线和图形相交的地方是一定的,并且都是矩形,所以线的长度会有最多 2n 个,用这 2n 条线长度乘上横坐标的距离(矩形的宽度),就可以把我们的总面积求出来咯</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> maxn 1<<21</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> ls (rt<<1)</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> rs (rt<<1|1)</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sline</span>{</span></span><br><span class="line"> <span class="keyword">int</span> x,h,l,k;</span><br><span class="line">}line[maxn];</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">setree</span>{</span></span><br><span class="line"> <span class="keyword">int</span> l,r,cnt,len;</span><br><span class="line">}t[maxn];</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">build</span><span class="params">(<span class="keyword">int</span> rt,<span class="keyword">int</span> l,<span class="keyword">int</span> r)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> t[rt].l=l;t[rt].r=r;</span><br><span class="line"> <span class="keyword">if</span>(l==r)<span class="keyword">return</span>;</span><br><span class="line"> <span class="keyword">int</span> mid=(t[rt].l+t[rt].r)>><span class="number">1</span>;</span><br><span class="line"> <span class="built_in">build</span>(ls,l,mid);</span><br><span class="line"> <span class="built_in">build</span>(rs,mid+<span class="number">1</span>,r);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> n,cnt;</span><br><span class="line"><span class="keyword">int</span> rk[maxn],val[maxn];</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">cmp</span><span class="params">(sline mm,sline nn)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> mm.x<nn.x;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">pushup</span><span class="params">(<span class="keyword">int</span> rt)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span>(t[rt].cnt)t[rt].len=val[t[rt].r+<span class="number">1</span>]-val[t[rt].l];</span><br><span class="line"> <span class="keyword">else</span> t[rt].len=t[ls].len+t[rs].len;</span><br><span class="line">}</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> rt,<span class="keyword">int</span> l,<span class="keyword">int</span> r,<span class="keyword">int</span> v)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span>(l<=t[rt].l&&r>=t[rt].r)</span><br><span class="line"> {</span><br><span class="line"> t[rt].cnt+=v;</span><br><span class="line"> <span class="built_in">pushup</span>(rt);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">int</span> mid=(t[rt].l+t[rt].r)>><span class="number">1</span>;</span><br><span class="line"> <span class="keyword">if</span>(l<=mid)<span class="built_in">add</span>(ls,l,r,v);</span><br><span class="line"> <span class="keyword">if</span>(r>mid)<span class="built_in">add</span>(rs,l,r,v);</span><br><span class="line"> <span class="built_in">pushup</span>(rt);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> ans;</span><br><span class="line"><span class="function"><span class="keyword">signed</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"> cin>>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++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> xx,x_x,yy,y_y,m=i<<<span class="number">1</span>;</span><br><span class="line"> cin>>xx>>yy>>x_x>>y_y;</span><br><span class="line"> line[(i << <span class="number">1</span>) - <span class="number">1</span>].x = xx, line[i << <span class="number">1</span>].x = x_x;</span><br><span class="line"> line[(i << <span class="number">1</span>) - <span class="number">1</span>].h = line[i << <span class="number">1</span>].h = y_y;</span><br><span class="line"> line[(i << <span class="number">1</span>) - <span class="number">1</span>].l = line[i << <span class="number">1</span>].l = yy;</span><br><span class="line"> line[(i << <span class="number">1</span>) - <span class="number">1</span>].k = <span class="number">1</span>, line[i << <span class="number">1</span>].k = <span class="number">-1</span>;</span><br><span class="line"> rk[++cnt]=yy;</span><br><span class="line"> rk[++cnt]=y_y;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">sort</span>(rk+<span class="number">1</span>,rk+<span class="number">2</span>*n+<span class="number">1</span>);</span><br><span class="line"> cnt=<span class="built_in">unique</span>(rk+<span class="number">1</span>,rk+<span class="number">2</span>*n+<span class="number">1</span>)-rk<span class="number">-1</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=<span class="number">2</span>*n;i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> p1=<span class="built_in">lower_bound</span>(rk+<span class="number">1</span>,rk+<span class="number">1</span>+cnt,line[i].h)-rk;</span><br><span class="line"> <span class="keyword">int</span> p2=<span class="built_in">lower_bound</span>(rk+<span class="number">1</span>,rk+<span class="number">1</span>+cnt,line[i].l)-rk;</span><br><span class="line"> val[p1]=line[i].h;</span><br><span class="line"> val[p2]=line[i].l;</span><br><span class="line"> line[i].h=p1;</span><br><span class="line"> line[i].l=p2;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">sort</span>(line+<span class="number">1</span>,line+<span class="number">1</span>+<span class="number">2</span>*n,cmp);</span><br><span class="line"> <span class="built_in">build</span>(<span class="number">1</span>,<span class="number">1</span>,<span class="number">2</span>*n);</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<<span class="number">2</span>*n;i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">add</span>(<span class="number">1</span>,line[i].l,line[i].h<span class="number">-1</span>,line[i].k);</span><br><span class="line"> ans+=t[<span class="number">1</span>].len*(line[i+<span class="number">1</span>].x-line[i].x);</span><br><span class="line"> }</span><br><span class="line"> cout<<ans<<endl;</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>
<p>有另一道题使用到了扫描线算法的(太累了不想写)<br>P1502 窗口的星星</p>
<h3 id="P4198-楼房重建题目链接"><a href="#P4198-楼房重建题目链接" class="headerlink" title="P4198 楼房重建题目链接"></a>P4198 楼房重建<a href="https://www.luogu.com.cn/problem/P4198">题目链接</a></h3><p>这道题是真的。。。很好。。。</p>
<p>首先很容易想到的是每一个数我们可以通过求斜率来判断是否能看见这栋楼</p>
<p>我们考虑答案,就是 1-n 这个区间之内,求单增的斜率个数最长递增的斜率</p>
<p>因为我们的区间是固定的,我们可以通过将区间分为两半进行处理,就可以想到使用线段树</p>
<p>线段树中维护两个信息:区间最大值和区间单增斜率数量</p>
<p>build,pushdown 都不需要。。。但是 pushup 操作就很烦。。。</p>
<p>最大值的 pushup 是很简单的,两个区间的最大值嘛</p>
<p>可是单增斜率数量是个很棘手的东西:</p>
<p>我们设 lx 为我 pushup 进这个大区间里,必须大于的最小值</p>
<p>先说边界:</p>
<p>如果 l==r 那 numk[rt]=a[l]>lx;如果只有一个元素,那么我如果递归的原来区间的最左端是比它大于等于的,那 numk[rt]=0,否则等于 1(显然)</p>
<p>对于我需要 pushup 的区间,左半边区间可以直接 pushup 上去,没影响,右半边要考虑和左半边儿子的关系,lx 便是左区间的最大值<br>考虑右儿子的左右两个子区间:</p>
<p>设 s1 为左区间 s2 为右区间 1.如果 s1 的最大值小于等于 lx 直接舍去递归 s2 2.如果 s1 的最大值大于 lx 那么我的 s2 里原本看不看得见的</p>
<p>直接 pushup 上去就可以,然而右半区间的看得见的应该是 numk[rk]-num[rk<em>2]而不是 numk[rk</em>2+1]因为右半区间有的是不能上去的</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> maxn 500010</span></span><br><span class="line"><span class="keyword">int</span> n, m;</span><br><span class="line"><span class="keyword">int</span> x[maxn], y[maxn];</span><br><span class="line"><span class="keyword">int</span> nk[maxn];</span><br><span class="line"><span class="keyword">double</span> t[maxn], lv[maxn];</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">pushup</span><span class="params">(<span class="keyword">double</span> lx, <span class="keyword">int</span> rt, <span class="keyword">int</span> l, <span class="keyword">int</span> r)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (t[rt] <= lx)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">if</span> (lv[l] > lx)</span><br><span class="line"> <span class="keyword">return</span> nk[rt];</span><br><span class="line"> <span class="keyword">if</span> (l == r)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</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">if</span> (t[rt * <span class="number">2</span>] <= lx)</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">pushup</span>(lx, rt * <span class="number">2</span> + <span class="number">1</span>, mid + <span class="number">1</span>, r);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">pushup</span>(lx, rt * <span class="number">2</span>, l, mid) + nk[rt] - nk[rt * <span class="number">2</span>];</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">change</span><span class="params">(<span class="keyword">int</span> rt, <span class="keyword">int</span> l, <span class="keyword">int</span> r, <span class="keyword">int</span> x, <span class="keyword">int</span> y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (l == r && r == x)</span><br><span class="line"> {</span><br><span class="line"> t[rt] = (<span class="keyword">double</span>)y/x;</span><br><span class="line"> nk[rt] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</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">if</span> (x <= mid)</span><br><span class="line"> <span class="built_in">change</span>(rt * <span class="number">2</span>, l, mid, x, y);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">change</span>(rt * <span class="number">2</span> + <span class="number">1</span>, mid + <span class="number">1</span>, r, x, y);</span><br><span class="line"> t[rt] = <span class="built_in">max</span>(t[rt * <span class="number">2</span>], t[rt * <span class="number">2</span> + <span class="number">1</span>]);</span><br><span class="line"> nk[rt] = <span class="built_in">pushup</span>(t[rt * <span class="number">2</span>], rt * <span class="number">2</span> + <span class="number">1</span>, mid + <span class="number">1</span>, r) + nk[rt * <span class="number">2</span>];</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">signed</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"> ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line"> cin >> n >> m;</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><br><span class="line"> {</span><br><span class="line"> cin >> x[i] >> y[i];</span><br><span class="line"> lv[x[i]] = (<span class="keyword">double</span>)y[i] / x[i];</span><br><span class="line"> <span class="built_in">change</span>(<span class="number">1</span>, <span class="number">1</span>, n, x[i], y[i]);</span><br><span class="line"> cout << nk[<span class="number">1</span>] << endl;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h1 id="撒花-完结-(终于-写完了)"><a href="#撒花-完结-(终于-写完了)" class="headerlink" title="撒花 完结 (终于**写完了)"></a>撒花 完结 (终于**写完了)</h1>]]></content>
<tags>
<tag>数据结构</tag>
</tags>
</entry>
<entry>
<title>组合数学</title>
<url>/%E7%BB%84%E5%90%88%E6%95%B0%E5%AD%A6/</url>
<content><![CDATA[<h1 id="组合数"><a href="#组合数" class="headerlink" title="组合数"></a>组合数</h1><h2 id="容斥-先鸽着吧"><a href="#容斥-先鸽着吧" class="headerlink" title="容斥 先鸽着吧"></a>容斥 <del>先鸽着吧</del></h2><p>1.(清华集训 主旋律)给定N个点的有向图,多少个强联通子图 N<=15</p>
<h4 id="解法"><a href="#解法" class="headerlink" title="解法"></a>解法</h4><p>(图里可能有$ N^2 $ 条边)爆搜过不去</p>
<h5 id="简单问题:给定一个有向图,问有多少个子图是DAG"><a href="#简单问题:给定一个有向图,问有多少个子图是DAG" class="headerlink" title="简单问题:给定一个有向图,问有多少个子图是DAG"></a>简单问题:给定一个有向图,问有多少个子图是DAG</h5><p>DP $ f[s] $表示在点集$S$之间删掉一些边使得剩下的图是一个$DAG$的方案数量</p>
<p>枚举哪些点的入度为0,然后递归<br>$$<br>f[s]=\sum_{T\subseteq S,T\neq \varnothing} 2^{edges(T,s-T)} \cdot f[S-T]<br>$$<br>但是这个递归式会算重复只保证了T中的入度为0,但是S-T里可能也有入度为0的点,所以就应该使用容斥<br>$$<br>f[s]=\sum_{T\subseteq S,T\neq \varnothing} 2^{edges(T,s-T)} \cdot f[S-T]\cdot (-1)^{|T|-1}<br>$$</p>
<p>使用这个DP,计算量是$ 3^N $, 枚举子集DP复杂度</p>
<h5 id="原题"><a href="#原题" class="headerlink" title="原题"></a>原题</h5><p>一个图如果不强联通的话,那么他就可以写成大于1个强连通分量连成的DAG</p>
<p>我们可以使用补集转化</p>
<p>强联通图的个数=所有图的个数 - 非强连通图的个数</p>
<p>尝试计算非强连通图的个数,枚举一个 ,让 连成一个强连通图, 不接受来自 </p>
<p>的边。<br>$$<br>f[s]=ALL(s)-\sum_{T\subseteq S,T\neq \varnothing}a[T]\cdot 2^{ways(T,S-T)}\cdot ALL(s)<br>$$<br>ALL(s)表示所有可能的图的个数,一样不对,会算重</p>
<p>令 $ g[T] $ 表示:把集合T划分成若干块,每一块重连成一个强连通块。如果有奇数个块,产生1的贡献,偶数产生-1的贡献</p>
<p> $ g[T] $是所有贡献之和<br>$$<br>f[s]=ALL(s)-\sum_{T\subseteq S,T\neq \varnothing}a[T]\cdot 2^{ways(T,S-T)}\cdot ALL(s)<br>$$<br>怎么算 g?</p>
<p>递归:给定一个集合S,固定$ x\in S $ ,枚举x所在的强连通块:<br>$$<br>g[S]=-\sum_{T\subseteq S ,x\in T}f[T]\cdot g[S-T]<br>$$</p>
<h1 id="组合计数"><a href="#组合计数" class="headerlink" title="组合计数"></a>组合计数</h1><p>常用公式:</p>
<h5 id="1-N-choose-K-N-K-N-K"><a href="#1-N-choose-K-N-K-N-K" class="headerlink" title="1.$ {N \choose K}=N!/(K!*(N-K)!)$"></a>1.$ {N \choose K}=N!/(K!*(N-K)!)$</h5><h5 id="2-sum-i-0-N-N-choose-I-2-N"><a href="#2-sum-i-0-N-N-choose-I-2-N" class="headerlink" title="2.$ \sum_{i=0}^{N}{N \choose I}=2^N$"></a>2.$ \sum_{i=0}^{N}{N \choose I}=2^N$</h5><h5 id="3-sum-i-0-N-N-choose-i-1-i-0"><a href="#3-sum-i-0-N-N-choose-i-1-i-0" class="headerlink" title="3.$\sum_{i=0}^{N}{N\choose i}(-1)^i=0$"></a>3.$\sum_{i=0}^{N}{N\choose i}(-1)^i=0$</h5><h5 id="4-sum-N-i-0-N-choose-i-x-i-1-x-N"><a href="#4-sum-N-i-0-N-choose-i-x-i-1-x-N" class="headerlink" title="4.$\sum_{N}^{i=0}{N\choose i}x^i=(1+x)^N$"></a>4.$\sum_{N}^{i=0}{N\choose i}x^i=(1+x)^N$</h5><h5 id="5-范德蒙公式:-sum-i-0-K-N-choose-i-M-choose-K-i-N-M-choose-K-sum-i-0-M-N-choose-i-M-choose-i-sum-i-N-choose-i-M-choose-M-i-N-M-choose-M"><a href="#5-范德蒙公式:-sum-i-0-K-N-choose-i-M-choose-K-i-N-M-choose-K-sum-i-0-M-N-choose-i-M-choose-i-sum-i-N-choose-i-M-choose-M-i-N-M-choose-M" class="headerlink" title="5.范德蒙公式:$\sum_{i=0}^{K}{N\choose i}{M\choose K-i}={N+M\choose K}$ $\sum_{i=0}^{M}{N\choose i}{M\choose i}=\sum_{i}{N\choose i}{M\choose M-i}={N+M\choose M}$"></a>5.范德蒙公式:$\sum_{i=0}^{K}{N\choose i}{M\choose K-i}={N+M\choose K}$ $\sum_{i=0}^{M}{N\choose i}{M\choose i}=\sum_{i}{N\choose i}{M\choose M-i}={N+M\choose M}$</h5><h5 id="6-重要:-N-choose-K-K-choose-i-N-choose-i-N-i-choose-K-i"><a href="#6-重要:-N-choose-K-K-choose-i-N-choose-i-N-i-choose-K-i" class="headerlink" title="6.重要:${N\choose K}{K\choose i}={N\choose i}{N-i\choose K-i}$"></a>6.重要:${N\choose K}{K\choose i}={N\choose i}{N-i\choose K-i}$</h5><p>理解:N个里选出来K个,再从K个之中选出i个,就相当于是在我的N中先选出来i个,再从剩下的N-i个之中选出来K-i个</p>
<p>经典场景:$\sum_k\sum_if(i){N\choose K}{K\choose i}=\sum_if(i)\sum_K{N\choose i}{N-i\choose K-i}=\sum_if(i){N\choose i}2^{N-i}$</p>
<h5 id="7-帕斯卡公式:-N-choose-i-N-1-choose-i-1-N-1-choose-i"><a href="#7-帕斯卡公式:-N-choose-i-N-1-choose-i-1-N-1-choose-i" class="headerlink" title="7.帕斯卡公式:${N\choose i}={N-1\choose i-1}+{N-1\choose i}$"></a>7.帕斯卡公式:${N\choose i}={N-1\choose i-1}+{N-1\choose i}$</h5><p>然后就可以推出来:${N+1\choose K+1}=\sum_{i=K}^{N}{i\choose K}$</p>
<p> 等价的:${N+1\choose K+1}=\sum_{i=K}^{N}{i\choose i-K}$(要对这个公式敏感一点)</p>
<p>这个公式有一个巧记的方法:</p>
<p>我枚举一个i,想象我选的第一个数是第i个,那么我还剩下N-i个物品,我要在这N-i个物品中选取K个,根据加法原理进行加和,就得出了这一个公式</p>
<p>另一种利用:$\sum_{i=0}^{K}{N+1\choose i}=\sum_i{N\choose i}+{N\choose i-1}=2\sum_{i=0}^{K}{N\choose i}-{N\choose K}$</p>
<p>可以运用杨辉三角形进行理解:上一行的所有数都向下产生了两倍于自己的贡献值,除了最后一个之外,所以我乘以二再减去末尾</p>
<p>似乎是另一种变形:$\sum_{k<=n}{r+k\choose k}={r\choose 0}+{r+1\choose 1}+···+{r+n\choose n}={r+n+1\choose n}$,其实相当于上面的那个等价帕斯卡公式</p>
<p>另一种名字叫做<strong>关于上指标求和</strong>,$\sum_{0<=k<=n}{k\choose m}={n+1\choose m+1},m,n>=0$</p>
<p>这两个个已通过对称性进行相互推出</p>
<h5 id="8-重要的一个东西:二项式定理:-x-y-r-sum-k-r-choose-k-x-ky-r-k-整数r-gt-0或者-x-y-lt-1"><a href="#8-重要的一个东西:二项式定理:-x-y-r-sum-k-r-choose-k-x-ky-r-k-整数r-gt-0或者-x-y-lt-1" class="headerlink" title="8.重要的一个东西:二项式定理:$(x+y)^r=\sum_{k}{r\choose k}x^ky^{r-k}$整数r>=0或者$|x/y|<1$"></a>8.重要的一个东西:二项式定理:$(x+y)^r=\sum_{k}{r\choose k}x^ky^{r-k}$整数r>=0或者$|x/y|<1$</h5><p>这个东西的很多特殊值是非常有用的比如1+1,1+(-1)一类的,可以用来推式子(比如容斥呀容斥呀容斥呀什么的……)</p>
<p>上面前几条性质都是二项式定理的特殊值,所以二项式定理还是很好用的……</p>
<p>推论:$0^n={n\choose 0}-{n\choose 1}+…+(-1)^n{n\choose n},n>=0$ (有一道题告诉我:同一行的(也就是上指标一样的)奇数二项式之和等于偶数二项式之和)(洛谷P5390数学作业,一个小绿题我做了老半天做不出来太恶心了)<a href="https://www.luogu.com.cn/problem/P5390">题目</a></p>
<h5 id="9-负数二项式:对于取负数值的n和取正数值的n,其-n-choose-k-之间有一种联系,一般的规则是:"><a href="#9-负数二项式:对于取负数值的n和取正数值的n,其-n-choose-k-之间有一种联系,一般的规则是:" class="headerlink" title="9. 负数二项式:对于取负数值的n和取正数值的n,其${n\choose k}$之间有一种联系,一般的规则是:"></a>9. 负数二项式:对于取负数值的n和取正数值的n,其${n\choose k}$之间有一种联系,一般的规则是:</h5><p>$$<br>{r\choose k}=(-1)^k{k-r-1\choose k}<br>$$</p>
<p>我们称之为:<strong>反转上指标</strong></p>
<h5 id="10-lucas定理"><a href="#10-lucas定理" class="headerlink" title="10. lucas定理"></a>10. lucas定理</h5><p>(我竟然把lucas放到了第十个)</p>
<p>对于p是质数的情况<br>$$<br>{n\choose m}\bmod p={n\bmod p\choose m\bmod p}*({n/p\choose m/p})\bmod p<br>$$</p>
<p>证明的过程我确实是不会。。。 (听说要用到生成函数知识)(以后再说)</p>
<p>lucas定理其实直接背过就可以了不需要理解 <del>因为根本理解不了</del></p>
<p>既然有了p是质数的情况,那么就应该有p不是质数的情况了吧:</p>
<p>扩展lucas定理横空出世<del>但是其实它和lucas定理没有任何的关系</del></p>
<p>我们在学习数论的时候是知道了一个东西叫做中国剩余定理的(简称韩信点兵<del>小学奥数</del>)</p>
<p>那么我们可以把p分解质因数,(由唯一分解定理</p>
<p>那么我们一定可以把p分解成若干个质数的多少次方相乘的形式</p>
<p>比如:$p={p_1}^{c_1} * {p_2}^{c_2} * … * {p_k}^s{c_k}$</p>
<p>那么我们求出${n\choose m}\bmod {p_1} ^ {c_1}$以及剩下的p2,p3…啊自用中国剩余定理合并一下就可以</p>
<p>但是在求得时候我们应该怎么求出来每一个式子呢?</p>
<p>我们把${n\choose m}$中$m!,n-m!,n!$中包含着$p_1$的项提出来,我们假设x为n!中是$p_1$的倍数的项,然后把它们提出来,变成这个样子:</p>
<p>$$<br>{n\choose m}\bmod{p_1}^{c_1} = \frac{\frac{n!}{ {p_1} ^ {x} } } {\frac{m! } { {p_1} ^ {y} }\frac{n-m!}{ {p_1 } ^ { z } } } * { p_1 } ^ { x-y-z } \bmod { p_1 } ^ { c_1 }<br>$$</p>
<p>就是把n!,m!和n-m!中p1的倍数全部都提取出来</p>
<p>那么这个xyz怎么求呢?</p>
<p>首先我们可以知道n以内的p的倍数总共有floor(n/p)个,但是n以内也有$p^2,p^3,p^4…$的倍数 </p>
<p>我们是需要把另外的p因子提出来,那么我们还需要求一遍n以内$p^2$的倍数,然后加上(因为之前已经加上了p的倍数,加过一次了,但是这些数字中含有两个p,就需要再加一次就够了(三次方四次方都一样</p>
<p>那么我们算出来的这个式子有什么用呢?<del>用处大了</del></p>
<p>既然我们把所有的p都提出来了,那么下面的东西就都互质了,就可以求逆元了</p>
<p>(就可以算了</p>
<p>那么我们还得考虑一下我们化简出来的这个式子的阶乘怎么算。。。</p>
<p>我们考虑这么一件事情:</p>
<p>p的倍数一定不和它互质,但是……只要不是p的倍数就一定不和他互质</p>
<p>那么我们可以发现一个规律就是,在我们求出来p-1的阶乘之后,p+1,p+2…2p-1这些数字在mod p的意义上是和1-p-1相同的,那么这就是一个循环的东西,就有规律。那么在最后的地方会剩下一点没有处理到的,特判一下就可以了</p>
<p><del>听 说 扩 展 Lucas 基 本 上 没 考 过 所 以 我 们 大 家 不 要 学 它</del></p>
<p><del>想 知 道 为 什 么 在 末 尾 才 说 他 不 考 吗 , 显 然 是 故 意 的 吧 /xyx</del></p>
<h1 id="排列组合例题:"><a href="#排列组合例题:" class="headerlink" title="排列组合例题:"></a>排列组合例题:</h1><h2 id="洛谷P2183-礼物"><a href="#洛谷P2183-礼物" class="headerlink" title="洛谷P2183 礼物"></a>洛谷P2183 礼物</h2><p><a href="https://www.luogu.com.cn/problem/P2183">题目链接</a></p>
<p>这个题是一个比较简单的排列组合的题。。。</p>
<p>其实就相当于是多重集合的排列而已嘛</p>
<p>我们把这个题转化一下:</p>
<p>不同的盒子,不同的球,盒子必须放满</p>
<p>那其实就相当于是:</p>
<p>盒子必须放满的话我们可以新创建一个盒子,用来放下剩下的没有盒子要的球,然后求一遍排列</p>
<p>那么我们考虑这么一件事情</p>
<p>对于两个1-n的排列来说,他们两个等价说明什么,说明在至少一个盒子里面,他们的球一样但是顺序不对</p>
<p>那我们就可以转化成多重集合的排列,一样的盒子里面的球变成一样的,只要有一个球到了其他的盒子里面而不是原来的盒子里面就说明是一种新的情况</p>
<p>但是这个题很恶心(好歹是个紫题)</p>
<p>他告诉我们说的是:模数不一定为质数(<del>真讨厌,国家集训队还出这种题</del></p>
<p>我们借鉴一下扩展lucas的思想</p>
<p>把上下的阶乘都化简一下,求出逆元就可以了</p>
<p><del>上面说的不考仅仅是指的NOI系列比赛</del></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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">1e5</span> + <span class="number">10</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> w[maxn];</span><br><span class="line"><span class="keyword">int</span> a[maxn], b[maxn];</span><br><span class="line"><span class="keyword">int</span> m, n;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">qpow</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y, <span class="keyword">int</span> mod)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> ans = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (y)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (y & <span class="number">1</span>)</span><br><span class="line"> ans *= x;</span><br><span class="line"> ans %= mod;</span><br><span class="line"> y >>= <span class="number">1</span>;</span><br><span class="line"> x *= x;</span><br><span class="line"> x %= mod;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> ans;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">exgcd</span><span class="params">(<span class="keyword">int</span> n, <span class="keyword">int</span> m, <span class="keyword">int</span> &x, <span class="keyword">int</span> &y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (!m)</span><br><span class="line"> <span class="keyword">return</span> (<span class="keyword">void</span>)(x = <span class="number">1</span>, y = <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">exgcd</span>(m, n % m, x, y);</span><br><span class="line"> <span class="keyword">int</span> huan = x;</span><br><span class="line"> x = y, y = huan - (n / m) * y;</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">F</span><span class="params">(<span class="keyword">int</span> n, <span class="keyword">int</span> p, <span class="keyword">int</span> pk)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (!n)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">int</span> rou = <span class="number">1</span>, res = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= pk; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (i % p)</span><br><span class="line"> (rou *= i) %= pk;</span><br><span class="line"> }</span><br><span class="line"> rou = <span class="built_in">qpow</span>(rou, n / pk, pk);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = pk * (n / pk); i <= n; i++)</span><br><span class="line"> <span class="keyword">if</span> (i % p)</span><br><span class="line"> res *= i % pk, res %= pk;</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">F</span>(n / p, p, pk) * res % pk * rou % pk;</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">G</span><span class="params">(<span class="keyword">int</span> n, <span class="keyword">int</span> p)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (n < p)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">G</span>(n / p, p) + n / p;</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">inv</span><span class="params">(<span class="keyword">int</span> a, <span class="keyword">int</span> mod)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> x, y;</span><br><span class="line"> <span class="built_in">exgcd</span>(a, mod, x, y);</span><br><span class="line"> <span class="keyword">return</span> (x + mod) % mod;</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">solve</span><span class="params">(<span class="keyword">int</span> p, <span class="keyword">int</span> pk)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> ans = <span class="built_in">F</span>(n, p, pk) % pk, num = <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><br><span class="line"> {</span><br><span class="line"> (ans *= (<span class="built_in">inv</span>(<span class="built_in">F</span>(w[i], p, pk), pk)) % pk) %= pk;</span><br><span class="line"> num += <span class="built_in">G</span>(w[i], p);</span><br><span class="line"> }</span><br><span class="line"> ans *= <span class="built_in">qpow</span>(p, <span class="built_in">G</span>(n, p) - num, pk);</span><br><span class="line"> ans %= pk;</span><br><span class="line"> <span class="keyword">return</span> ans;</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">calc</span><span class="params">(<span class="keyword">int</span> n, <span class="keyword">int</span> m, <span class="keyword">int</span> mod)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> now = mod, tot = <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 * i <= mod; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> ((now % i) == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> pk = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> ((now % i) == <span class="number">0</span>)</span><br><span class="line"> pk *= i, now /= i;</span><br><span class="line"> a[++tot] = pk, b[tot] = <span class="built_in">solve</span>(i, pk);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (now != <span class="number">1</span>)</span><br><span class="line"> a[++tot] = now, b[tot] = <span class="built_in">solve</span>(now, now);</span><br><span class="line"> <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 <= tot; ++i)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> M = mod / a[i], T = <span class="built_in">inv</span>(M, a[i]);</span><br><span class="line"> ans += M * T % mod * b[i] % mod;</span><br><span class="line"> ans %= mod;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> ans % mod;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">signed</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"> ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"in.txt"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"out.txt"</span>, <span class="string">"w"</span>, stdout);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"> <span class="keyword">int</span> mod;</span><br><span class="line"> cin >> mod >> n >> m;</span><br><span class="line"> <span class="keyword">int</span> sum = <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><br><span class="line"> {</span><br><span class="line"> cin >> w[i];</span><br><span class="line"> sum += w[i];</span><br><span class="line"> <span class="keyword">if</span> (sum > n)</span><br><span class="line"> {</span><br><span class="line"> cout << <span class="string">"Impossible"</span> << endl;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (sum < n)</span><br><span class="line"> {</span><br><span class="line"> m++;</span><br><span class="line"> w[m] = n - sum;</span><br><span class="line"> }</span><br><span class="line"> cout << <span class="built_in">calc</span>(n, m, mod) << endl;</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>
<h2 id="P3223-排队"><a href="#P3223-排队" class="headerlink" title="P3223 排队"></a>P3223 排队</h2><p><a href="https://www.luogu.com.cn/problem/P3223">题目链接</a></p>
<p>这个题大水题好吧</p>
<p><del>高 精 度 啊 对 不 起 打 扰 了</del></p>
<p><del>我 没 写 所 以 就 不 放 代 码 了 。 。 。</del></p>
<p>这道题还是比较水的吧,一眼题</p>
<p>我们把男同学和老师看做板子,用插板法</p>
<p>我们先把两个老师随便的情况算出来,然后算出强制让两个老师站在一起的方案数</p>
<p>两者相减就是答案</p>
<h2 id="BZOJ-2467-生成树"><a href="#BZOJ-2467-生成树" class="headerlink" title="BZOJ 2467 生成树"></a>BZOJ 2467 生成树</h2><p><a href="https://darkbzoj.tk/problem/2467">题目链接</a></p>
<p>这个题还是比较简单的(我在课上切了没和ZRQ说做法</p>
<p><del>(我不会证明</del></p>
<p>我们可以手膜一遍发现一个小结论:在几个五边形都各自随便断掉一条边的情况下,会出现正好一个环(然后随便断一条边就可以了……</p>
<p>所以说我们就相当于一个五边形断掉两条边,其他的断掉一条边就可以了</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> mod = <span class="number">2007</span>;</span><br><span class="line"><span class="keyword">int</span> n;</span><br><span class="line"><span class="keyword">int</span> ans;</span><br><span class="line"><span class="function"><span class="keyword">signed</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;</span><br><span class="line"> cin >> t;</span><br><span class="line"> <span class="keyword">while</span> (t--)</span><br><span class="line"> {</span><br><span class="line"> cin >> n;</span><br><span class="line"> ans = <span class="number">4</span> * n;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= n - <span class="number">1</span>; i++)</span><br><span class="line"> ans *= <span class="number">5</span>, ans %= mod;</span><br><span class="line"> cout << ans << endl;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"><span class="comment">//极短对不对。。。</span></span><br></pre></td></tr></table></figure>
<h2 id="BZOJ-3782-上学路线"><a href="#BZOJ-3782-上学路线" class="headerlink" title="BZOJ 3782 上学路线"></a>BZOJ 3782 上学路线</h2><p><a href="https://darkbzoj.tk/problem/3782">题目链接</a></p>
<p>这个题还是比较妙的一个题</p>
<p>首先我们考虑:</p>
<p>对于一个点(x,y)来说,到他的方案数是不是就是不经过它左下角任意一个点的方案数</p>
<p>那么我们就可以用容斥</p>
<p>考虑如果经过左下角的点的话:</p>
<p>我们枚举第一个经过的点,钦定这个点一定会被经过,这个点的左下角的点一定不被经过,</p>
<p>由于是枚举进行求解,我们是知道从源点到左下角的方案数的(不经过任何障碍</p>
<p>从这个点走道我们当前计算的点的时候就直接组合数进行计算(求解方案数的时候直接组合数求向上走的方案数</p>
<p>然后就算完了</p>
<p>(请注意模数哦,要用CRT进行求解的</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">1e6</span> + <span class="number">5</span>;</span><br><span class="line"><span class="keyword">int</span> n, m, t, p[<span class="number">10</span>], P;</span><br><span class="line"><span class="keyword">int</span> fac[<span class="number">5</span>][maxn], inv[<span class="number">5</span>][maxn], M[<span class="number">5</span>], invm[<span class="number">5</span>];</span><br><span class="line"><span class="keyword">int</span> f[maxn];</span><br><span class="line"><span class="keyword">bool</span> flag;</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="class">{</span></span><br><span class="line"> <span class="keyword">int</span> x, y;</span><br><span class="line">} pos[maxn];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">cmp</span><span class="params">(node x, node y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (x.x == y.x)</span><br><span class="line"> <span class="keyword">return</span> x.y < y.y;</span><br><span class="line"> <span class="keyword">return</span> x.x < y.x;</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">qpow</span><span class="params">(<span class="keyword">int</span> a, <span class="keyword">int</span> b, <span class="keyword">int</span> mod)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> ret = <span class="number">1</span>;</span><br><span class="line"> a %= mod;</span><br><span class="line"> <span class="keyword">while</span> (b)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (b & <span class="number">1</span>)</span><br><span class="line"> ret = <span class="number">1ll</span> * ret * a % mod;</span><br><span class="line"> a = <span class="number">1ll</span> * a * a % mod, b >>= <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> ret;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">C</span><span class="params">(<span class="keyword">int</span> a, <span class="keyword">int</span> b, <span class="keyword">int</span> i)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (a < b)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> b = <span class="built_in">min</span>(b, a - b);</span><br><span class="line"> <span class="keyword">if</span> (!b)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">if</span> (a < p[i] && b < p[i])</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1ll</span> * fac[i][a] * inv[i][b] % p[i] * inv[i][a - b] % p[i];</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1ll</span> * <span class="built_in">C</span>(a % p[i], b % p[i], i) * <span class="built_in">C</span>(a / p[i], b / p[i], i) % p[i];</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">calc</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (!flag)</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">C</span>(x, y, <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">int</span> res = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">int</span> g[<span class="number">10</span>];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= <span class="number">4</span>; i++)</span><br><span class="line"> g[i] = <span class="built_in">C</span>(x, y, i);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= <span class="number">4</span>; i++)</span><br><span class="line"> res += (g[i] * M[i] % P * invm[i] % P), res %= P;</span><br><span class="line"> <span class="keyword">return</span> res;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">signed</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="meta">#<span class="meta-keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"in.txt"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"out.txt"</span>, <span class="string">"w"</span>, stdout);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"> ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line"></span><br><span class="line"> cin >> n >> m >> t >> P;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= t; i++)</span><br><span class="line"> cin >> pos[i].x >> pos[i].y;</span><br><span class="line"></span><br><span class="line"> pos[++t] = {n, m};</span><br><span class="line"></span><br><span class="line"> <span class="built_in">sort</span>(pos + <span class="number">1</span>, pos + <span class="number">1</span> + t, cmp);</span><br><span class="line"> p[<span class="number">0</span>] = <span class="number">1000003</span>, p[<span class="number">1</span>] = <span class="number">3</span>, p[<span class="number">2</span>] = <span class="number">5</span>, p[<span class="number">3</span>] = <span class="number">6793</span>, p[<span class="number">4</span>] = <span class="number">10007</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (P != <span class="number">1000003</span>)</span><br><span class="line"> flag = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (flag)</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 <= <span class="number">4</span>; i++)</span><br><span class="line"> {</span><br><span class="line"> M[i] = P / p[i];</span><br><span class="line"> invm[i] = <span class="built_in">qpow</span>(M[i], p[i] - <span class="number">2</span>, p[i]);</span><br><span class="line"></span><br><span class="line"> fac[i][<span class="number">0</span>] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">1</span>; j < p[i]; j++)</span><br><span class="line"> fac[i][j] = fac[i][j - <span class="number">1</span>] * j % p[i];</span><br><span class="line"></span><br><span class="line"> inv[i][p[i] - <span class="number">1</span>] = <span class="built_in">qpow</span>(fac[i][p[i] - <span class="number">1</span>], p[i] - <span class="number">2</span>, p[i]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = p[i] - <span class="number">1</span>; j >= <span class="number">1</span>; j--)</span><br><span class="line"> inv[i][j - <span class="number">1</span>] = inv[i][j] * j % p[i];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> fac[<span class="number">0</span>][<span class="number">0</span>] = <span class="number">1</span>;</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 <= P - <span class="number">1</span>; i++)</span><br><span class="line"> fac[<span class="number">0</span>][i] = fac[<span class="number">0</span>][i - <span class="number">1</span>] * i % P;</span><br><span class="line"></span><br><span class="line"> inv[<span class="number">0</span>][P - <span class="number">1</span>] = <span class="built_in">qpow</span>(fac[<span class="number">0</span>][P - <span class="number">1</span>], P - <span class="number">2</span>, P);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = p[i] - <span class="number">1</span>; i >= <span class="number">1</span>; i--)</span><br><span class="line"> inv[<span class="number">0</span>][i - <span class="number">1</span>] = inv[<span class="number">0</span>][i] * i % P;</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 <= t; i++)</span><br><span class="line"> {</span><br><span class="line"> f[i] = <span class="built_in">calc</span>(pos[i].x + pos[i].y, <span class="built_in">min</span>(pos[i].x, pos[i].y));</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">1</span>; j < i; j++)</span><br><span class="line"> <span class="keyword">if</span> (pos[i].x >= pos[j].x && pos[i].y >= pos[j].y)</span><br><span class="line"> f[i] -= <span class="built_in">calc</span>(pos[i].x + pos[i].y - pos[j].x - pos[j].y, pos[i].x - pos[j].x) * f[j], f[i] %= P, f[i] += P, f[i] %= P;</span><br><span class="line"> }</span><br><span class="line"> cout << f[t] % P;</span><br><span class="line"> <span class="built_in">puts</span>(<span class="string">""</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>
<h2 id="P3166-数三角形"><a href="#P3166-数三角形" class="headerlink" title="P3166 数三角形"></a>P3166 数三角形</h2><p><a href="https://www.luogu.com.cn/problem/P3166">题目链接</a></p>
<p>这个题挺好的,就是难度有一点点的虚高。。。(最多是个蓝的绝对到不了紫</p>
<p>显然我们就可以想到容斥</p>
<p>我们只要求出来三点共线的方案数就可以了</p>
<p>首先:三点共线是分不同的情况的:横着,竖着,斜着</p>
<p>那横竖都好求,就是斜着的时候不太好求</p>
<p>我们手膜一下,我们会发现,一个点到一个距离它为(x,y)的点上连线的时候,这条<strong>线段</strong>上的格点数量应该是gcd(x,y)+1</p>
<p>那么我们枚举一下线段,只是枚举从原点开始的点,求出来方案数</p>
<p>那么我们还可以发现,我们求不了其他点为原点时候的方案(线段的方案数在下面</p>
<p>真的吗?</p>
<p>显然假的</p>
<p>我们可以把这个线段进行一下平移,平移之后就可以出现其他的了(并且我们只考虑斜率为正的线段,最后需要乘上2</p>
<p>那么这条线段能平移出来几条线段呢?显然是(n-x)*(m-y)条把 </p>
<p>那么还有一个问题:</p>
<p>这个线段上的可选的点会不会重复选呢?</p>
<p>好解决:我们枚举线段的时候,将两端的点设为必选,那么三点共线的方案数就是gcd(x,y)-1了,不需要考虑起点终点因为有平移的话不需要考虑</p>
<p>然后就做完了(这个题好歹没有CRT这种坑货的东西</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">2010</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> n, m;</span><br><span class="line"><span class="keyword">int</span> xie[maxn][maxn];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">gcd</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (!y)</span><br><span class="line"> <span class="keyword">return</span> x;</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">gcd</span>(y, x % y);</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">C3</span><span class="params">(<span class="keyword">int</span> x)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> x * (x - <span class="number">1</span>) * (x - <span class="number">2</span>) / <span class="number">6</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">signed</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="meta">#<span class="meta-keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"in.txt"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"out.txt"</span>, <span class="string">"w"</span>, stdout);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</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 >> n >> m;</span><br><span class="line"> ++n, ++m;</span><br><span class="line"> <span class="keyword">int</span> ans = <span class="built_in">C3</span>(n * m);</span><br><span class="line"> ans -= <span class="built_in">C3</span>(n) * m + <span class="built_in">C3</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++)</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">1</span>; j <= m; j++)</span><br><span class="line"> ans -= <span class="number">2</span> * (<span class="built_in">gcd</span>(i, j) - <span class="number">1</span>) * (n - i) * (m - j);</span><br><span class="line"> cout << ans << endl;</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>
<h2 id="P2606-排列计数"><a href="#P2606-排列计数" class="headerlink" title="P2606 排列计数"></a>P2606 排列计数</h2><p><a href="https://www.luogu.com.cn/problem/P2606">题目链接</a></p>
<p>这个题我感觉其实和上面数三角形差不多…(但是这个题的评级还可以)</p>
<p>这个题其实就相当于是让我们求一遍小根堆的个数。。。(手膜转化一下)</p>
<p>那我们其实只要dp一下就可以了</p>
<p>设f[i]为以i为根的小根堆的方案数</p>
<p>那么f[i]是可以通过来求出左右子树来进行方案数的排列的</p>
<p>$f[i]=f[ i << 1 ] * f[ (i<<1) | 1 ] * { siz[i] - 1 \choose siz[ i<<1 ] }$</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">1e7</span> + <span class="number">10</span>;</span><br><span class="line"><span class="keyword">int</span> f[maxn * <span class="number">2</span>], n, mod, jie[maxn], siz[maxn];</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">qpow</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y, <span class="keyword">int</span> mod)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> ans = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (y)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (y & <span class="number">1</span>)</span><br><span class="line"> ans *= x;</span><br><span class="line"> ans %= mod;</span><br><span class="line"> (x *= x) %= mod;</span><br><span class="line"> y >>= <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> ans;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">inv</span><span class="params">(<span class="keyword">int</span> now)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">qpow</span>(jie[now], mod - <span class="number">2</span>, mod) % mod;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">C</span><span class="params">(<span class="keyword">int</span> n, <span class="keyword">int</span> m)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (n < m)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">return</span> jie[n] * <span class="built_in">inv</span>(m) % mod * <span class="built_in">inv</span>(n - m) % mod;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">lucas</span><span class="params">(<span class="keyword">int</span> n, <span class="keyword">int</span> m)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (n < mod && m < mod)</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">C</span>(n, m);</span><br><span class="line"> <span class="keyword">if</span> (!m)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">C</span>(n % mod, m % mod) * <span class="built_in">lucas</span>(n / mod, m / mod) % mod;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">signed</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="meta">#<span class="meta-keyword">ifndef</span> ONLINE_JUDGE</span></span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"in.txt"</span>, <span class="string">"r"</span>, stdin);</span><br><span class="line"> <span class="built_in">freopen</span>(<span class="string">"out.txt"</span>, <span class="string">"w"</span>, stdout);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</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 >> n >> mod;</span><br><span class="line"> jie[<span class="number">0</span>] = <span class="number">1</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"> jie[i] = (jie[i - <span class="number">1</span>] * i) % mod;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = n; i >= <span class="number">1</span>; i--)</span><br><span class="line"> {</span><br><span class="line"> siz[i]++;</span><br><span class="line"> siz[i / <span class="number">2</span>] += siz[i];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = n; i >= <span class="number">1</span>; i--)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (((i << <span class="number">1</span>) | <span class="number">1</span>) > n)</span><br><span class="line"> {</span><br><span class="line"> f[i] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> f[i] = f[i << <span class="number">1</span>] * f[(i << <span class="number">1</span>) | <span class="number">1</span>] % mod * <span class="built_in">lucas</span>(siz[i] - <span class="number">1</span>, siz[(i << <span class="number">1</span>)]);</span><br><span class="line"> f[i] %= mod;</span><br><span class="line"> }</span><br><span class="line"> cout << f[<span class="number">1</span>] << endl;</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>网络流初步</title>
<url>/%E7%BD%91%E7%BB%9C%E6%B5%81%E5%88%9D%E6%AD%A5/</url>
<content><![CDATA[<h1 id="网络流初步"><a href="#网络流初步" class="headerlink" title="网络流初步"></a>网络流初步</h1><p>(寒假集训听了听i207M学长的课,感觉收获颇丰啊</p>
<h1 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h1><p>老样子,先从定义开始:</p>
<ul>
<li><strong>网络</strong>:网络是指一个有向图,$G=(V,E)$,V是点集,E是边集,对于任意的$(u,v)\in V$,都对应的有一个边权,这个边权代表一个限制性的东西,我们称之为<strong>容量</strong>。我们定义一条边属于一个网络里,有且仅有,联通且容量不为0。另外,特殊的是,在一个网络中必定存在两个特殊的点,<strong>源点S</strong>和<strong>汇点V</strong>,表示起点和终点。</li>
<li><strong>网络流</strong>:我们规定从源点到汇点的所有流量之和为整个网络的流量。流必须满足以下的几个性质:</li>
</ul>
<ol>
<li><p><strong>容量限制</strong>,对于每一条边来说,我们经过其的实际流量不得超过它的最大流量</p>
</li>
<li><p><strong>斜对称性</strong>:每一条边和它的<strong>相反边</strong>(相反边是很重要的哦)的实际流量之和为0</p>
</li>
<li><p><strong>流守恒性</strong>:从源点流出的流量等于汇点所接受的流量</p>
</li>
<li><p><strong>剩余容量</strong>:最大流量-实际流量</p>
<p>我们可以将网络流形象地比作一个下水道系统(原谅我这个不太恰当的比喻),我们从城市的废水系统处接受总的水流(无限大),接收到源点,系统中分布着很多的管道,但是管道们有粗有细,有长有短,所以它们的极限流量不一样,我们要将废水运至汇点进行处理,那么我们就需要求出网络中的水流大小(汇点可以接收到的水流),但是不一样的是,在水流经过的时候,我们的管道中并不能储存或产生废水,从源点流入水就将从汇点流入水。</p>
</li>
</ol>
<p>那么我们可以自然而然的想到:我最大可以从源点到汇点流过多少水呢?</p>
<p>引出下一个概念 :最大流</p>
<h1 id="最大流"><a href="#最大流" class="headerlink" title="最大流"></a>最大流</h1><h2 id="定义-1"><a href="#定义-1" class="headerlink" title="定义"></a>定义</h2><ul>
<li><strong>残量网络</strong>:在已经求得一部分容量后,所有的边的以自己的剩余容量所组成的一条网络称为残量网络,特殊的,在网络还并没有任何的流量的时候,残量网络就是原来的网络;</li>
<li><strong>增广路</strong>:一条从源点到汇点的剩余容量都大于0的路径被称为增广路。(也可以说在残量网络的一条从源点到汇点的路径)</li>
<li><strong>最大流</strong>:从源点到汇点的最大流量</li>
</ul>
<p>虽然我们可以将网络流比作一个下水道系统,但实际上,这个下水道系统并不具有气压……各处的水面并不是一样平的,有的道路可能并不会被走过,有的道路可能会被走满,有的道路可能只会走一半。这就说明在一个网络里,不同的走的方案得到的流量是不一样的,所以我们就要进行最大流的求解。(这里只介绍OI中常用的最大流算法:dinic算法</p>
<h2 id="dinic-算法求解最大流:"><a href="#dinic-算法求解最大流:" class="headerlink" title="dinic 算法求解最大流:"></a>dinic 算法求解最大流:</h2><p>dinic算法本质上是求出一条一条的增广路,然后将增广路的流量都加起来之后的最大值就可以成为这个网络的最大流。</p>
<p>第一步是进行分层处理:首先用BFS对残量网络进行分层,我们设源点的层数为0(1也可以随你心情),那么一个点的层数就是它距离源点的最近距离(以边权角度来说的最近距离)</p>
<p>那么分层的目的是什么呢?</p>
<p>分层有两个目的:</p>
<ol>
<li>如果不存在增广路了,就直接停止算法进程</li>
<li>确保我们找到的增广路是最短的(下面有原因</li>
</ol>
<p>接下来就是用dfs寻找增广路的过程了:我们每一次寻找增广路的时候,都只是寻找下一层的节点进行更新(只要有剩余容量就进行更新)</p>
<p>如果下面看代码的时候你会发现我会在反边里加上容量,原因是:如果仅仅是上述操作的话不一定更可以求出最大流,所以我们需要进行回溯,dfs寻找其他的增广路,那么我们就有必要在反边上进行改变,那样在回溯的时候就又可以变回原来的容量了(是在下面的另外一次BFS的时候的(但是我并不是很理解建反边的实际作用,或者说实际的流程)(希望有大佬科普)</p>
<p>dinic算法有两个优化:</p>
<ol>
<li><strong>多路增广</strong>: 每次找到一条增广路的时候,如果残量网络并没有用完呢?我们可以利用参与部分流量,再找出一条增广路。这样就可以在一次的BFS中找到多条的增广路</li>
<li><strong>当前弧优化</strong>:如果我们当前的边已经被增广过了,那就没有必要在进行一次增广了,肯定没有可能去增广第二次了。那么我们下一次进行增广的时候就不需要再进行一次增广了。原因:在一条边被增广过了,只会有几种情况:一种是它上面的边溜过来的流量不够了,一种是它下面的边被填满了,另一种是它自己被填满了,不论是哪一种,我们如果再次对它进行增广,都不会产生任何贡献</li>
</ol>
<p>这么一看dinic算法的复杂度其实挺不好的,毕竟每次进行新一轮的增广的时候都需要重新一次BFS,还需要一轮的DFS,复杂度似乎是$N^2M$级别的复杂度,但事实证明,dinic算法在平常的图中是可以跑过1e4~1e5级别的数据的(别问我为什么我也不知道)(是在加了两个优化的前提之下)</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">1010</span>;</span><br><span class="line"><span class="keyword">int</span> d[maxn];</span><br><span class="line"><span class="keyword">int</span> n, m, s, t;</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="class">{</span></span><br><span class="line"> <span class="keyword">int</span> y, z, nex;</span><br><span class="line">} e[<span class="number">10010</span> * <span class="number">2</span>];</span><br><span class="line"><span class="keyword">int</span> head[maxn], tot = <span class="number">1</span>, hd[maxn];<span class="comment">/*tot=1是大细节……</span></span><br><span class="line"><span class="comment">如果你的邻接表在写的时候经常是用的++tot的话,</span></span><br><span class="line"><span class="comment">那写网络流的时候一定要记得把tot初始化为1,</span></span><br><span class="line"><span class="comment">因为下面的异或操作,</span></span><br><span class="line"><span class="comment">1异或之后是0而不是2……</span></span><br><span class="line"><span class="comment">奇数和偶数之间的异或就会乱掉</span></span><br><span class="line"><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> z)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> e[++tot] = {y, z, head[x]};</span><br><span class="line"> head[x] = tot;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> ans;</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">bfs</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>(d, <span class="number">0</span>, <span class="built_in"><span class="keyword">sizeof</span></span>(d));</span><br><span class="line"> queue<<span class="keyword">int</span>> q;</span><br><span class="line"> q.<span class="built_in">push</span>(s);</span><br><span class="line"> d[s] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (!q.<span class="built_in">empty</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x = q.<span class="built_in">front</span>();</span><br><span class="line"> q.<span class="built_in">pop</span>();</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = head[x]; i; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (e[i].z && !d[v])<span class="comment">//残量网络</span></span><br><span class="line"> {</span><br><span class="line"> d[v] = d[x] + <span class="number">1</span>;</span><br><span class="line"> q.<span class="built_in">push</span>(v);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> d[t];</span><br><span class="line"> <span class="comment">//一遍普普通通的BFS,用来求我们的深度</span></span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">dfs</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> in)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (x == t || !in)</span><br><span class="line"> <span class="keyword">return</span> in;</span><br><span class="line"> <span class="keyword">int</span> out = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> &i = hd[x]; i && in; i = e[i].nex)<span class="comment">//这里是当前弧优化</span></span><br><span class="line"> <span class="comment">//我不能够走某些边了(当前弧嘛),那么我直接从根源处扔掉它(就是邻接表)(下面每一次bfs是都是需要重新给赋值的</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (e[i].z && d[v] == d[x] + <span class="number">1</span>)<span class="comment">//必须是下一层的才可以进行增广,并且要在残量网络中</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> res = <span class="built_in">dfs</span>(v, <span class="built_in">min</span>(e[i].z, in));</span><br><span class="line"> e[i].z -= res;</span><br><span class="line"> e[i ^ <span class="number">1</span>].z += res;<span class="comment">//反边</span></span><br><span class="line"> in -= res;</span><br><span class="line"> out += res;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> out;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">signed</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"> ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line"> cin >> n >> m >> s >> t;</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><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x, y, z;</span><br><span class="line"> cin >> x >> y >> z;</span><br><span class="line"> <span class="built_in">add</span>(x, y, z);</span><br><span class="line"> <span class="built_in">add</span>(y, x, <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">bfs</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">memcpy</span>(hd, head, <span class="built_in"><span class="keyword">sizeof</span></span>(head));</span><br><span class="line"> ans += <span class="built_in">dfs</span>(s, <span class="number">1e18</span>);</span><br><span class="line"> }</span><br><span class="line"> cout << ans << endl;</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>
<h2 id="例题"><a href="#例题" class="headerlink" title="例题"></a>例题</h2><h3 id="P2891-Dining-G"><a href="#P2891-Dining-G" class="headerlink" title="P2891 Dining G"></a>P2891 Dining G</h3><p><a href="https://www.luogu.com.cn/problem/P2891">题目链接</a></p>
<p>上来就给这道题还是很有意义的,因为这道题要用到网络流中一个经典的套路叫做拆点</p>
<p>拆点一般适用于那种对于一个点有流量限制的图中 </p>
<p>这道题也很简单,首先是将食物与牛连边,牛对应自己喜欢的食物,然后是牛和饮料连边,对应自己喜欢的饮料</p>
<p>然后我们跑一遍最大流,思路就差不多了</p>
<p>但是这样对了但不完全对了</p>
<p>我们要对牛有一个容量限制,因为每头牛只吃一种食物,喝一种饮料,所以在牛处我们需要拆点</p>
<p>并且还需要对食物和饮料有限制,因为一种食物和一种饮料只有一个,所以在源点和汇点处连边的时候要记住容量为1</p>
<p>最后跑一遍最大流</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">5010</span>;</span><br><span class="line"><span class="keyword">int</span> n, d, f;</span><br><span class="line"><span class="keyword">int</span> head[maxn], tot = <span class="number">1</span>;</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="class">{</span></span><br><span class="line"> <span class="keyword">int</span> y, z, nex;</span><br><span class="line">} e[maxn];</span><br><span class="line"><span class="keyword">int</span> dep[maxn];</span><br><span class="line"><span class="keyword">int</span> s, t;</span><br><span class="line"><span class="keyword">namespace</span> scan</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">template</span> <<span class="keyword">typename</span> T></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="keyword">void</span> <span class="title">read</span><span class="params">(T &x)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> x = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">char</span> c = <span class="built_in">getchar</span>();</span><br><span class="line"> <span class="keyword">int</span> f = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (; !<span class="built_in">isdigit</span>(c); c = <span class="built_in">getchar</span>())</span><br><span class="line"> f |= c == <span class="string">'-'</span>;</span><br><span class="line"> <span class="keyword">for</span> (; <span class="built_in">isdigit</span>(c); c = <span class="built_in">getchar</span>())</span><br><span class="line"> x = x * <span class="number">10</span> + (c ^ <span class="number">48</span>);</span><br><span class="line"> <span class="keyword">if</span> (f)</span><br><span class="line"> x = -x;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">template</span> <<span class="keyword">typename</span> T, <span class="keyword">typename</span>... Args></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="keyword">void</span> <span class="title">read</span><span class="params">(T &x, Args &...args)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="built_in">read</span>(x), <span class="built_in">read</span>(args...);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">template</span> <<span class="keyword">typename</span> T></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="keyword">void</span> <span class="title">write</span><span class="params">(T x, <span class="keyword">char</span> ch)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (x < <span class="number">0</span>)</span><br><span class="line"> <span class="built_in">putchar</span>(<span class="string">'-'</span>), x = -x;</span><br><span class="line"> <span class="keyword">static</span> <span class="keyword">short</span> st[<span class="number">30</span>], tp;</span><br><span class="line"> <span class="keyword">do</span></span><br><span class="line"> st[++tp] = x % <span class="number">10</span>, x /= <span class="number">10</span>;</span><br><span class="line"> <span class="keyword">while</span> (x);</span><br><span class="line"> <span class="keyword">while</span> (tp)</span><br><span class="line"> <span class="built_in">putchar</span>(st[tp--] | <span class="number">48</span>);</span><br><span class="line"> <span class="built_in">putchar</span>(ch);</span><br><span class="line"> }</span><br><span class="line">}<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> z)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> e[++tot] = {y, z, head[x]};</span><br><span class="line"> head[x] = tot;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> scan;</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">bfs</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>(dep, <span class="number">0</span>, <span class="built_in"><span class="keyword">sizeof</span></span>(dep));</span><br><span class="line"> dep[s] = <span class="number">1</span>;</span><br><span class="line"> queue<<span class="keyword">int</span>> q;</span><br><span class="line"> q.<span class="built_in">push</span>(s);</span><br><span class="line"> <span class="keyword">while</span> (!q.<span class="built_in">empty</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x = q.<span class="built_in">front</span>();</span><br><span class="line"> q.<span class="built_in">pop</span>();</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = head[x]; i; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (!e[i].z || dep[v])</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> dep[v] = dep[x] + <span class="number">1</span>;</span><br><span class="line"> q.<span class="built_in">push</span>(v);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> dep[t];</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">dfs</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> in)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (x == t || !in)</span><br><span class="line"> <span class="keyword">return</span> in;</span><br><span class="line"> <span class="keyword">int</span> out = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = head[x]; i && in; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (dep[v] != dep[x] + <span class="number">1</span> || !e[i].z)</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">int</span> res = <span class="built_in">dfs</span>(v, <span class="built_in">min</span>(e[i].z, in));</span><br><span class="line"> out += res;</span><br><span class="line"> in -= res;</span><br><span class="line"> e[i].z -= res;</span><br><span class="line"> e[i ^ <span class="number">1</span>].z += res;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (!out)</span><br><span class="line"> dep[x] = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">return</span> out;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> ans;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dinic</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">bfs</span>())</span><br><span class="line"> ans += <span class="built_in">dfs</span>(s, <span class="number">1e18</span>);</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">fi</span><span class="params">(<span class="keyword">int</span> x)</span> </span>{ <span class="keyword">return</span> x + <span class="number">1</span>; }</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">di</span><span class="params">(<span class="keyword">int</span> x)</span> </span>{ <span class="keyword">return</span> <span class="number">1</span> + x + n + f; }</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">d1</span><span class="params">(<span class="keyword">int</span> x)</span> </span>{ <span class="keyword">return</span> <span class="number">1</span> + x + f; }</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">d2</span><span class="params">(<span class="keyword">int</span> x)</span> </span>{ <span class="keyword">return</span> <span class="number">1</span> + x + f + d + n; }</span><br><span class="line"><span class="comment">//拆点的时候,d1代表是的牛的第一个点,d2代表牛的第二个,fi,di代表的是食物和饮料(顺序就不要太介意了</span></span><br><span class="line"><span class="function"><span class="keyword">signed</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">read</span>(n, f, d);</span><br><span class="line"> s = <span class="number">1</span>, t = <span class="number">2010</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= f; i++)</span><br><span class="line"> <span class="built_in">add</span>(s, <span class="built_in">fi</span>(i), <span class="number">1</span>), <span class="built_in">add</span>(<span class="built_in">fi</span>(i), s, <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 <= d; i++)</span><br><span class="line"> <span class="built_in">add</span>(<span class="built_in">di</span>(i), t, <span class="number">1</span>), <span class="built_in">add</span>(t, <span class="built_in">di</span>(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 <= n; i++)</span><br><span class="line"> <span class="built_in">add</span>(<span class="built_in">d1</span>(i), <span class="built_in">d2</span>(i), <span class="number">1</span>), <span class="built_in">add</span>(<span class="built_in">d2</span>(i), <span class="built_in">d1</span>(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 <= n; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> F, D;</span><br><span class="line"> <span class="built_in">read</span>(F, D);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">1</span>; j <= F; j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x;</span><br><span class="line"> <span class="built_in">read</span>(x);</span><br><span class="line"> <span class="built_in">add</span>(<span class="built_in">fi</span>(x), <span class="built_in">d1</span>(i), <span class="number">1</span>), <span class="built_in">add</span>(<span class="built_in">d1</span>(i), <span class="built_in">fi</span>(x), <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">1</span>; j <= D; j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x;</span><br><span class="line"> <span class="built_in">read</span>(x);</span><br><span class="line"> <span class="built_in">add</span>(<span class="built_in">d2</span>(i), <span class="built_in">di</span>(x), <span class="number">1</span>), <span class="built_in">add</span>(<span class="built_in">di</span>(x), <span class="built_in">d2</span>(i), <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">dinic</span>();</span><br><span class="line"> <span class="built_in">write</span>(ans, <span class="string">'\n'</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">首先我们可以知道这道题我们直接把饮料,牛,食物进行连边,跑一遍网络流可以得到答案。(粗略想法</span></span><br><span class="line"><span class="comment">但是我们可以发现一件事情就是,一头牛吃了一个食物,一个饮料别的牛不可以再吃</span></span><br><span class="line"><span class="comment">那么我们就需要对流量进行限制</span></span><br><span class="line"><span class="comment">网络流的经典套路之一:拆点</span></span><br><span class="line"><span class="comment">我们将每一头牛都拆成两个点,两个点之间连一条边,限制住我们的流量为1,就可以保证流过一头牛唯一</span></span><br><span class="line"><span class="comment">再将源点和汇点连边的流量都设成1</span></span><br><span class="line"><span class="comment">就可以保证一个食物,一个饮料只给一头牛</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure>
<h1 id="最小割"><a href="#最小割" class="headerlink" title="最小割"></a>最小割</h1><h2 id="定义:"><a href="#定义:" class="headerlink" title="定义:"></a>定义:</h2><p>对于一个网络来说,存在着一种边的划分,使得源点和汇点不连通,这个方案被称为是网络的一个割</p>
<p><strong>最小割</strong>:顾名思义,边权和最小的一个割被称为最小割</p>
<h3 id="最大流最小割定理"><a href="#最大流最小割定理" class="headerlink" title="最大流最小割定理"></a>最大流最小割定理</h3><p>最大流等于最小割</p>
<h2 id="例题-1"><a href="#例题-1" class="headerlink" title="例题"></a>例题</h2><p>P2774 方格取数问题</p>
<p><a href="https://www.luogu.com.cn/problem/P2774">题目链接</a></p>
<p>任意两个数没有公共边,并且取出的数最大</p>
<p>那么我们改变一下连边的策略的话:</p>
<p>我们把横纵坐标加起来为奇数的格子染成黑色,偶数的染成白色,我们让源点和黑色的格子连边,黑色的格子和相邻的白色格子连边,白色格子与汇点连边,这样构成了一个网络,那么我们求出这个网络的最小割就相当于求出了有什么点我是不选的,用所有点的权值和减掉最小割的权值就可以得到答案</p>
<p>容量的限制就可以是:黑点和源点之间的边容量为点权,白点和汇点之间的边容量也是点权,黑白点之间的边容量为inf,这样求出的最小割肯定是黑点或者白点的权值</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">1100</span>;</span><br><span class="line"><span class="keyword">int</span> m, n;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxx = <span class="number">1e9</span> + <span class="number">50000</span>;</span><br><span class="line"><span class="keyword">int</span> d[maxn];</span><br><span class="line"><span class="keyword">int</span> ans;</span><br><span class="line"><span class="keyword">int</span> s, t;</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="class">{</span></span><br><span class="line"> <span class="keyword">int</span> y, z, nex;</span><br><span class="line">} e[maxn * maxn * <span class="number">4</span>];</span><br><span class="line"><span class="keyword">int</span> head[maxn * maxn * <span class="number">2</span>], tot = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">namespace</span> scan</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">template</span> <<span class="keyword">typename</span> T></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="keyword">void</span> <span class="title">read</span><span class="params">(T &x)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> x = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">char</span> c = <span class="built_in">getchar</span>();</span><br><span class="line"> <span class="keyword">int</span> f = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (; !<span class="built_in">isdigit</span>(c); c = <span class="built_in">getchar</span>())</span><br><span class="line"> f |= c == <span class="string">'-'</span>;</span><br><span class="line"> <span class="keyword">for</span> (; <span class="built_in">isdigit</span>(c); c = <span class="built_in">getchar</span>())</span><br><span class="line"> x = x * <span class="number">10</span> + (c ^ <span class="number">48</span>);</span><br><span class="line"> <span class="keyword">if</span> (f)</span><br><span class="line"> x = -x;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">template</span> <<span class="keyword">typename</span> T, <span class="keyword">typename</span>... Args></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="keyword">void</span> <span class="title">read</span><span class="params">(T &x, Args &...args)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="built_in">read</span>(x), <span class="built_in">read</span>(args...);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">template</span> <<span class="keyword">typename</span> T></span><br><span class="line"> <span class="function"><span class="keyword">inline</span> <span class="keyword">void</span> <span class="title">write</span><span class="params">(T x, <span class="keyword">char</span> ch)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (x < <span class="number">0</span>)</span><br><span class="line"> <span class="built_in">putchar</span>(<span class="string">'-'</span>), x = -x;</span><br><span class="line"> <span class="keyword">static</span> <span class="keyword">short</span> st[<span class="number">30</span>], tp;</span><br><span class="line"> <span class="keyword">do</span></span><br><span class="line"> st[++tp] = x % <span class="number">10</span>, x /= <span class="number">10</span>;</span><br><span class="line"> <span class="keyword">while</span> (x);</span><br><span class="line"> <span class="keyword">while</span> (tp)</span><br><span class="line"> <span class="built_in">putchar</span>(st[tp--] | <span class="number">48</span>);</span><br><span class="line"> <span class="built_in">putchar</span>(ch);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> scan;</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> z)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> e[++tot] = {y, z, head[x]};</span><br><span class="line"> head[x] = tot;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> sum;</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">bfs</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>(d, <span class="number">0</span>, <span class="built_in"><span class="keyword">sizeof</span></span>(d));</span><br><span class="line"> d[s] = <span class="number">1</span>;</span><br><span class="line"> queue<<span class="keyword">int</span>> q;</span><br><span class="line"> q.<span class="built_in">push</span>(s);</span><br><span class="line"> <span class="keyword">while</span> (!q.<span class="built_in">empty</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x = q.<span class="built_in">front</span>();</span><br><span class="line"> q.<span class="built_in">pop</span>();</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = head[x]; i; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (d[v] || !e[i].z)</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> d[v] = d[x] + <span class="number">1</span>;</span><br><span class="line"> q.<span class="built_in">push</span>(v);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> d[t];</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">dfs</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> in)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (x == t || !in)</span><br><span class="line"> <span class="keyword">return</span> in;</span><br><span class="line"> <span class="keyword">int</span> out = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = head[x]; i && in; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (!e[i].z || d[v] != d[x] + <span class="number">1</span>)</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">int</span> res = <span class="built_in">dfs</span>(v, <span class="built_in">min</span>(e[i].z, in));</span><br><span class="line"> out += res;</span><br><span class="line"> in -= res;</span><br><span class="line"> e[i].z -= res;</span><br><span class="line"> e[i ^ <span class="number">1</span>].z += res;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (!out)</span><br><span class="line"> d[x] = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">return</span> out;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> dx[<span class="number">4</span>] = {<span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">-1</span>};</span><br><span class="line"><span class="keyword">int</span> dy[<span class="number">4</span>] = {<span class="number">1</span>, <span class="number">-1</span>, <span class="number">0</span>, <span class="number">0</span>};</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">dis</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> (x - <span class="number">1</span>) * n + y + <span class="number">1</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">signed</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">read</span>(m, n);</span><br><span class="line"> s = <span class="number">1</span>, t = m * n + <span class="number">10</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><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">1</span>; j <= n; j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> now;</span><br><span class="line"> <span class="built_in">read</span>(now);</span><br><span class="line"> sum += now;</span><br><span class="line"> <span class="keyword">if</span> ((i + j) % <span class="number">2</span> == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">add</span>(s, <span class="built_in">dis</span>(i, j), now);</span><br><span class="line"> <span class="built_in">add</span>(<span class="built_in">dis</span>(i, j), s, <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k = <span class="number">0</span>; k < <span class="number">4</span>; k++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x = i + dx[k], y = j + dy[k];</span><br><span class="line"> <span class="keyword">if</span> (x >= <span class="number">1</span> && x <= m && y <= n && y >= <span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">add</span>(<span class="built_in">dis</span>(i, j), <span class="built_in">dis</span>(x, y), maxx);</span><br><span class="line"> <span class="built_in">add</span>(<span class="built_in">dis</span>(x, y), <span class="built_in">dis</span>(i, j), <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">add</span>(<span class="built_in">dis</span>(i, j), t, now);</span><br><span class="line"> <span class="built_in">add</span>(t, <span class="built_in">dis</span>(i, j), <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">bfs</span>())</span><br><span class="line"> ans += <span class="built_in">dfs</span>(s, maxx);</span><br><span class="line"> <span class="built_in">write</span>(sum - ans, <span class="string">'\n'</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h1 id="最小费用最小流"><a href="#最小费用最小流" class="headerlink" title="最小费用最小流"></a>最小费用最小流</h1><p>(简称费用流)</p>
<h2 id="定义-2"><a href="#定义-2" class="headerlink" title="定义"></a>定义</h2><p>给定一个网络,这个网络不只是有容量限制,每一条边还有一个费用,代表流过1的流量需要的花费,要在最大流的前提下求出最小费用</p>
<p>和最大流算法差不多,只是我们在寻找增广路的时候是需要优先按照费用进行寻找而非边距,所以我们要用SPFA算法来进行分层</p>
<p>在建图的时候,是需要把费用也放到边的另一个权值上面的,那么反向边的费用呢?反向边的费用应该为正向边的相反数(显然把……总不能重复走</p>
<p>也有用dijkstra的,但我不会</p>
<p>时间复杂度极度玄学</p>
<p>理论上界nmf,f是最大流</p>
<p>以洛谷板子题:P3381为例子</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">5e3</span> + <span class="number">10</span>;</span><br><span class="line"><span class="keyword">int</span> n, m, s, t;</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="class">{</span></span><br><span class="line"> <span class="keyword">int</span> y, z, w, nex;</span><br><span class="line">} e[maxn * <span class="number">20</span>];</span><br><span class="line"><span class="keyword">int</span> head[maxn], tot = <span class="number">1</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> z, <span class="keyword">int</span> w)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> e[++tot] = {y, z, w, head[x]};</span><br><span class="line"> head[x] = tot;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> d[maxn], vis[maxn];</span><br><span class="line"><span class="keyword">int</span> hd[maxn];</span><br><span class="line"><span class="keyword">int</span> ans, cost;</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">spfa</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>(d, <span class="number">0x3f</span>, <span class="built_in"><span class="keyword">sizeof</span></span>(d));</span><br><span class="line"> <span class="built_in">memset</span>(vis, <span class="number">0</span>, <span class="built_in"><span class="keyword">sizeof</span></span>(vis));</span><br><span class="line"> queue<<span class="keyword">int</span>> q;</span><br><span class="line"> d[s] = <span class="number">0</span>;</span><br><span class="line"> q.<span class="built_in">push</span>(s);</span><br><span class="line"> <span class="keyword">while</span> (!q.<span class="built_in">empty</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x = q.<span class="built_in">front</span>();</span><br><span class="line"> q.<span class="built_in">pop</span>();</span><br><span class="line"> vis[x] = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = head[x]; i; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (e[i].z && d[v] > d[x] + e[i].w)</span><br><span class="line"> {</span><br><span class="line"> d[v] = d[x] + e[i].w;</span><br><span class="line"> <span class="keyword">if</span> (!vis[v])</span><br><span class="line"> vis[v] = <span class="number">1</span>, q.<span class="built_in">push</span>(v);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> d[t] != <span class="number">0x3f3f3f3f3f3f3f3f</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">dfs</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> in)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (x == t || !in)</span><br><span class="line"> <span class="keyword">return</span> in;</span><br><span class="line"> <span class="keyword">int</span> out = <span class="number">0</span>;</span><br><span class="line"> vis[x] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> &i = hd[x]; i && in; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (vis[v] || !e[i].z || d[v] != d[x] + e[i].w)</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">int</span> res = <span class="built_in">dfs</span>(v, <span class="built_in">min</span>(in, e[i].z));</span><br><span class="line"> out += res;</span><br><span class="line"> in -= res;</span><br><span class="line"> e[i].z -= res;</span><br><span class="line"> e[i ^ <span class="number">1</span>].z += res;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> out;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dinic</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">spfa</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">memcpy</span>(hd, head, <span class="built_in"><span class="keyword">sizeof</span></span>(head));</span><br><span class="line"> <span class="keyword">int</span> k = <span class="built_in">dfs</span>(s, <span class="number">1e18</span>);</span><br><span class="line"> ans += k;</span><br><span class="line"> cost += k * d[t];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">signed</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"> ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line"> cin >> n >> m >> s >> t;</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><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x, y, z, w;</span><br><span class="line"> cin >> x >> y >> z >> w;</span><br><span class="line"> <span class="built_in">add</span>(x, y + n, z, w);</span><br><span class="line"> <span class="built_in">add</span>(y + n, x, <span class="number">0</span>, -w);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">dinic</span>();</span><br><span class="line"> cout << ans << <span class="string">' '</span> << cost << endl;</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>
<h2 id="例题:P2153-晨跑"><a href="#例题:P2153-晨跑" class="headerlink" title="例题:P2153 晨跑"></a>例题:P2153 晨跑</h2><p><a href="https://www.luogu.com.cn/problem/P2153">题目链接</a></p>
<p>既然题目中说了:路程最短,时间最长,那这不就是费用流问题,时间为流量,路程为费用,我们在连边的时候,流量为1,并且拆点,把每一个点拆成两个并且流量为1,费用为0,这样保证这一个点只会经过一次,一条边的费用就是它的路程,然后跑一遍费用流就结束。</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">810</span>;</span><br><span class="line"><span class="keyword">int</span> s, t;</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="class">{</span></span><br><span class="line"> <span class="keyword">int</span> y, z, w, nex;</span><br><span class="line">} e[<span class="number">20010</span>*<span class="number">4</span>];</span><br><span class="line"><span class="keyword">int</span> head[maxn * <span class="number">2</span>], tot = <span class="number">1</span>, hd[maxn * <span class="number">2</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">add</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y, <span class="keyword">int</span> z, <span class="keyword">int</span> w)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> e[++tot] = {y, z, w, head[x]};</span><br><span class="line"> head[x] = tot;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> ans, cost;</span><br><span class="line"><span class="keyword">int</span> d[maxn], vis[maxn];</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">spfa</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> queue<<span class="keyword">int</span>> q;</span><br><span class="line"> <span class="built_in">memset</span>(d, <span class="number">0x3f</span>, <span class="built_in"><span class="keyword">sizeof</span></span>(d));</span><br><span class="line"> <span class="built_in">memset</span>(vis, <span class="number">0</span>, <span class="built_in"><span class="keyword">sizeof</span></span>(vis));</span><br><span class="line"> d[s] = <span class="number">0</span>;</span><br><span class="line"> q.<span class="built_in">push</span>(s);</span><br><span class="line"> <span class="keyword">while</span> (!q.<span class="built_in">empty</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x = q.<span class="built_in">front</span>();</span><br><span class="line"> q.<span class="built_in">pop</span>();</span><br><span class="line"> vis[x] = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = head[x]; i; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (e[i].z && d[v] > d[x] + e[i].w)</span><br><span class="line"> {</span><br><span class="line"> d[v] = d[x] + e[i].w;</span><br><span class="line"> <span class="keyword">if</span> (!vis[v])</span><br><span class="line"> vis[v] = <span class="number">1</span>, q.<span class="built_in">push</span>(v);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> d[t] != <span class="number">0x3f3f3f3f3f3f3f3f</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">dfs</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> in)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (x == t || !in)</span><br><span class="line"> <span class="keyword">return</span> in;</span><br><span class="line"> <span class="keyword">int</span> out = <span class="number">0</span>;</span><br><span class="line"> vis[x] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> &i = hd[x]; i && in; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (!e[i].z || d[v] != d[x] + e[i].w || vis[v])</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">int</span> res = <span class="built_in">dfs</span>(v, <span class="built_in">min</span>(in, e[i].z));</span><br><span class="line"> e[i].z -= res;</span><br><span class="line"> e[i ^ <span class="number">1</span>].z += res;</span><br><span class="line"> out += res;</span><br><span class="line"> in -= res;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> out;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dinic</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">spfa</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">memcpy</span>(hd, head, <span class="built_in"><span class="keyword">sizeof</span></span>(head));</span><br><span class="line"> <span class="keyword">int</span> k = <span class="built_in">dfs</span>(s, <span class="number">1e18</span>);</span><br><span class="line"> ans += k;</span><br><span class="line"> cost += k * d[t];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">signed</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"> cin >> n >> m;</span><br><span class="line"> <span class="keyword">while</span> (m--)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x, y, z;</span><br><span class="line"> cin >> x >> y >> z;</span><br><span class="line"> <span class="built_in">add</span>(x + n, y, <span class="number">1</span>, z);</span><br><span class="line"> <span class="built_in">add</span>(y, x + n, <span class="number">0</span>, -z);</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><br><span class="line"> <span class="built_in">add</span>(i, i + n, <span class="number">1</span>, <span class="number">0</span>), <span class="built_in">add</span>(i + n, i, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"> s = <span class="number">1</span> + n, t = n;</span><br><span class="line"> <span class="built_in">dinic</span>();</span><br><span class="line"> cout << ans << <span class="string">' '</span> << cost << endl;</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>
<h1 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h1><h2 id="P4016-负载平衡问题"><a href="#P4016-负载平衡问题" class="headerlink" title="P4016 负载平衡问题"></a>P4016 负载平衡问题</h2><p><a href="https://www.luogu.com.cn/problem/P4016">题目链接</a></p>
<p>虽然在图上的环形问题很讨厌,但总比在序列上的好……(比如某群</p>
<p>(其实这道题完全可以不用网络流做,这可以用中位数做</p>
<p>我们对每一个点进行拆分,拆成两个不同的节点,一个是供应节点,另一个是需求节点,最后剩下的值应该是所有的平均数,那么边权就应该是当前值与平均数之间的偏移(当前值-平均数</p>
<p>如果偏移大于零说明这个点需要向外进行供应,就让它和源点连边,边权为偏移</p>
<p>小于零说明这个点需要向内输入,就让它和汇点连边,边权为偏移的绝对值</p>
<p>然后考虑相邻的节点之间的关系,由于相邻的节点之间是可以相互运送货物的,那么</p>
<p>相邻节点之间相互补充,把两个点的供应节点和需求节点相连,容量为无穷大,费用为1</p>
<p>相邻节点进行转运工作,把两个点的供应节点相连,容量为无穷大,费用为1</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">210</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxx = <span class="number">0x3f3f3f3f3f3f3f3f</span>;</span><br><span class="line"><span class="keyword">int</span> n;</span><br><span class="line"><span class="keyword">int</span> a[maxn];</span><br><span class="line"><span class="keyword">int</span> sum;</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="class">{</span></span><br><span class="line"> <span class="keyword">int</span> y, z, w, nex;</span><br><span class="line">} e[maxn * <span class="number">10</span>];</span><br><span class="line"><span class="keyword">int</span> head[maxn], tot = <span class="number">1</span>, hd[maxn];</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> z, <span class="keyword">int</span> w)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> e[++tot] = {y, z, w, head[x]};</span><br><span class="line"> head[x] = tot;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> s, t;</span><br><span class="line"><span class="keyword">int</span> cost;</span><br><span class="line"><span class="keyword">int</span> d[maxn], vis[maxn];</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">spfa</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> queue<<span class="keyword">int</span>> q;</span><br><span class="line"> <span class="built_in">memset</span>(d, <span class="number">0x3f</span>, <span class="built_in"><span class="keyword">sizeof</span></span>(d));</span><br><span class="line"> <span class="built_in">memset</span>(vis, <span class="number">0</span>, <span class="built_in"><span class="keyword">sizeof</span></span>(vis));</span><br><span class="line"> d[s] = <span class="number">0</span>;</span><br><span class="line"> q.<span class="built_in">push</span>(s);</span><br><span class="line"> <span class="keyword">while</span> (!q.<span class="built_in">empty</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x = q.<span class="built_in">front</span>();</span><br><span class="line"> q.<span class="built_in">pop</span>();</span><br><span class="line"> vis[x] = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = head[x]; i; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (e[i].z && d[v] > d[x] + e[i].w)</span><br><span class="line"> {</span><br><span class="line"> d[v] = d[x] + e[i].w;</span><br><span class="line"> <span class="keyword">if</span> (!vis[v])</span><br><span class="line"> vis[v] = <span class="number">1</span>, q.<span class="built_in">push</span>(v);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> d[t] != <span class="number">0x3f3f3f3f3f3f3f3f</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">dfs</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> in)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (x == t || !in)</span><br><span class="line"> <span class="keyword">return</span> in;</span><br><span class="line"> <span class="keyword">int</span> out = <span class="number">0</span>;</span><br><span class="line"> vis[x] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> &i = hd[x]; i && in; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (!e[i].z || d[v] != d[x] + e[i].w || vis[v])</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">int</span> res = <span class="built_in">dfs</span>(v, <span class="built_in">min</span>(in, e[i].z));</span><br><span class="line"> e[i].z -= res;</span><br><span class="line"> e[i ^ <span class="number">1</span>].z += res;</span><br><span class="line"> out += res;</span><br><span class="line"> in -= res;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> out;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dinic</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">spfa</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">memcpy</span>(hd, head, <span class="built_in"><span class="keyword">sizeof</span></span>(head));</span><br><span class="line"> <span class="keyword">int</span> k = <span class="built_in">dfs</span>(s, <span class="number">1e18</span>);</span><br><span class="line"> cost += k * d[t];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">signed</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"> cin >> n;</span><br><span class="line"> s = <span class="number">0</span>, t = n + <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>, x; i <= n; ++i)</span><br><span class="line"> {</span><br><span class="line"> cin >> x;</span><br><span class="line"> <span class="built_in">add</span>(s, i, x, <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">add</span>(i, s, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"> sum += x;</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><br><span class="line"> {</span><br><span class="line"> <span class="built_in">add</span>(i, t, sum / n, <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">add</span>(t, i, <span class="number">0</span>, <span class="number">0</span>);</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><br><span class="line"> {</span><br><span class="line"> <span class="built_in">add</span>(i, i + <span class="number">1</span>, maxx, <span class="number">1</span>);</span><br><span class="line"> <span class="built_in">add</span>(i + <span class="number">1</span>, i, <span class="number">0</span>, <span class="number">-1</span>);</span><br><span class="line"> } </span><br><span class="line"> <span class="built_in">add</span>(n, <span class="number">1</span>, maxx, <span class="number">1</span>), <span class="built_in">add</span>(<span class="number">1</span>, n, <span class="number">0</span>, <span class="number">-1</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">2</span>; i <= n; ++i)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">add</span>(i, i - <span class="number">1</span>, maxx, <span class="number">1</span>);</span><br><span class="line"> <span class="built_in">add</span>(i - <span class="number">1</span>, i, <span class="number">0</span>, <span class="number">-1</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">add</span>(<span class="number">1</span>, n, maxx, <span class="number">1</span>), <span class="built_in">add</span>(n, <span class="number">1</span>, <span class="number">0</span>, <span class="number">-1</span>);</span><br><span class="line"> <span class="built_in">dinic</span>();</span><br><span class="line"> cout << cost << endl;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h2 id="P2770-航空路线问题"><a href="#P2770-航空路线问题" class="headerlink" title="P2770 航空路线问题"></a>P2770 航空路线问题</h2><p><a href="https://www.luogu.com.cn/problem/P4016">题目链接</a></p>
<p>我们先把题目进行一次转化:在网络上找到两条从源点到汇点的路径且不相交</p>
<p>那么我们可以很容易的把流量搞明白,每条边的流量为1,拆点,流量为1,最后源点出去的流量每一条边为1,汇点的流量在进行限制为2(或者在跑最大流的时候有while循环,只要流量已经为2了就停止增广(一次增广最多增加1的流量</p>
<p>那么我们考虑题目中的经过最多城市</p>
<p>我们走过的边中一定会含有我们没有走过的城市,那我们走过一条边就一定会到一个城市,那么我们将边的费用设置成1,跑一遍最大费用最大流就可以解决</p>
<p>题目还要求我们输出方案,那么直接进行一次DFS,将网络中 容量已经为0的边进行遍历,(容量为0说明走过,容量为1说明没走过</p>
<p> 输出答案即可,注意不要重复输出最后一个点</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">110</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxx = <span class="number">0x3f3f3f3f3f3f3f3f</span>;</span><br><span class="line">map<string, <span class="keyword">int</span>> Map;</span><br><span class="line"><span class="keyword">int</span> n, m;</span><br><span class="line"><span class="keyword">int</span> d[maxn], vis[maxn];</span><br><span class="line"><span class="keyword">int</span> S, T;</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="class">{</span></span><br><span class="line"> <span class="keyword">int</span> y, z, w, nex;</span><br><span class="line">} e[maxn * maxn];</span><br><span class="line"><span class="keyword">int</span> head[maxn], tot = <span class="number">1</span>, hd[maxn];</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> z, <span class="keyword">int</span> w)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> e[++tot] = {y, z, w, head[x]};</span><br><span class="line"> head[x] = tot;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> pos[maxn];</span><br><span class="line">string s[maxn];</span><br><span class="line"><span class="keyword">int</span> cost, ans;</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">spfa</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>(d, <span class="number">0x3f</span>, <span class="built_in"><span class="keyword">sizeof</span></span>(d));</span><br><span class="line"> <span class="built_in">memset</span>(vis, <span class="number">0</span>, <span class="built_in"><span class="keyword">sizeof</span></span>(vis));</span><br><span class="line"> queue<<span class="keyword">int</span>> q;</span><br><span class="line"> q.<span class="built_in">push</span>(S);</span><br><span class="line"> d[S] = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span> (!q.<span class="built_in">empty</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x = q.<span class="built_in">front</span>();</span><br><span class="line"> q.<span class="built_in">pop</span>();</span><br><span class="line"> vis[x] = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = head[x]; i; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (e[i].z && d[v] > d[x] + e[i].w)</span><br><span class="line"> {</span><br><span class="line"> d[v] = d[x] + e[i].w;</span><br><span class="line"> <span class="keyword">if</span> (!vis[v])</span><br><span class="line"> {</span><br><span class="line"> vis[v] = <span class="number">1</span>;</span><br><span class="line"> q.<span class="built_in">push</span>(v);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> d[T] != maxx;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">dfs</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> in)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (x == T || !in)</span><br><span class="line"> <span class="keyword">return</span> in;</span><br><span class="line"> <span class="keyword">int</span> out = <span class="number">0</span>;</span><br><span class="line"> vis[x] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> &i = hd[x]; i && in; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (!e[i].z || vis[v] || d[v] != d[x] + e[i].w)</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">int</span> res = <span class="built_in">dfs</span>(v, <span class="built_in">min</span>(in, e[i].z));</span><br><span class="line"> out += res;</span><br><span class="line"> in -= res;</span><br><span class="line"> e[i].z -= res;</span><br><span class="line"> e[i ^ <span class="number">1</span>].z += res;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> out;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dinic</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">spfa</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">memcpy</span>(hd, head, <span class="built_in"><span class="keyword">sizeof</span></span>(head));</span><br><span class="line"> <span class="keyword">int</span> k = <span class="built_in">dfs</span>(S, <span class="number">1e18</span>);</span><br><span class="line"> ans += k;</span><br><span class="line"> cost += k * d[T];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dfs1</span><span class="params">(<span class="keyword">int</span> x)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> cout << s[x - n] << endl;</span><br><span class="line"> vis[x] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = head[x]; i; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (!e[i].z)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">dfs1</span>(e[i].y + n);</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="function"><span class="keyword">void</span> <span class="title">dfs2</span><span class="params">(<span class="keyword">int</span> x)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> vis[x] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = head[x]; i; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (!e[i].z && !vis[v + n])</span><br><span class="line"> <span class="built_in">dfs2</span>(v + n);</span><br><span class="line"> }</span><br><span class="line"> cout << s[x - n] << endl;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">signed</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">bool</span> flag = <span class="number">0</span>;</span><br><span class="line"> cin >> n >> m;</span><br><span class="line"> S = <span class="number">1</span>, T = n * <span class="number">2</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><br><span class="line"> cin >> s[i];</span><br><span class="line"> Map[s[i]] = i;</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 <= m; i++)</span><br><span class="line"> {</span><br><span class="line"> string s1, s2;</span><br><span class="line"> cin >> s1 >> s2;</span><br><span class="line"> <span class="keyword">int</span> pos1 = Map[s1], pos2 = Map[s2];</span><br><span class="line"> <span class="keyword">if</span> (pos1 > pos2)</span><br><span class="line"> <span class="built_in">swap</span>(pos1, pos2);</span><br><span class="line"> <span class="built_in">add</span>(pos1 + n, pos2, <span class="number">1</span>, <span class="number">-1</span>);</span><br><span class="line"> <span class="built_in">add</span>(pos2, pos1 + n, <span class="number">0</span>, <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">if</span> (pos1 == <span class="number">1</span> && pos2 == n)</span><br><span class="line"> flag = <span class="number">1</span>;</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><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (i != <span class="number">1</span> && i != n)</span><br><span class="line"> <span class="built_in">add</span>(i, i + n, <span class="number">1</span>, <span class="number">0</span>), <span class="built_in">add</span>(i + n, i, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">add</span>(i, i + n, <span class="number">2</span>, <span class="number">0</span>), <span class="built_in">add</span>(i + n, i, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">dinic</span>();</span><br><span class="line"> <span class="keyword">if</span> (ans == <span class="number">1</span> && flag == <span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> cout << <span class="number">2</span> << endl;</span><br><span class="line"> cout << s[<span class="number">1</span>] << endl;</span><br><span class="line"> cout << s[n] << endl;</span><br><span class="line"> cout << s[<span class="number">1</span>] << endl;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (ans != <span class="number">2</span>)</span><br><span class="line"> {</span><br><span class="line"> cout << <span class="string">"No Solution!"</span> << endl;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> cout << -cost << endl;</span><br><span class="line"> <span class="built_in">dfs1</span>(S + n);</span><br><span class="line"> <span class="built_in">dfs2</span>(S + n);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="P2766最长不下降子序列问题"><a href="#P2766最长不下降子序列问题" class="headerlink" title="P2766最长不下降子序列问题"></a>P2766最长不下降子序列问题</h2><p><a href="https://www.luogu.com.cn/problem/P4016">题目链接</a></p>
<p>首先第一问可以直接用一个$n^2dp$搞出来,这里就先不说了吧</p>
<p>第二问开始就需要用到网络流了</p>
<p>由于每一个元素只能使用一次,那就说明如果用到网络流的话,这个元素可以进行拆点之后流量为1</p>
<p>然后呢?图怎么建呢?</p>
<p>我们考虑在dp的过程中我们都干了些什么?</p>
<p>我们在每一次转移之前都在向前找,找到比自己小于等于的数,转移。</p>
<p>那么,网络流时建边,也就是小数向大数建边</p>
<p>我们应该让当前点向前找,如果找到了一个数,它的dp值是这个点dp值减1,就连一条容量为1的边,源点向每一个dp值为1的点连边,每一个dp值为s的点向汇点连边</p>
<p>第三问呢?</p>
<p>第1和第n个点可以重复利用就说明……不需要拆点了!</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">100010</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxx = <span class="number">1e18</span>;</span><br><span class="line"><span class="keyword">int</span> n;</span><br><span class="line"><span class="keyword">int</span> a[maxn / <span class="number">2</span>];</span><br><span class="line"><span class="keyword">int</span> d[maxn];</span><br><span class="line"><span class="keyword">int</span> f[maxn];</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="class">{</span></span><br><span class="line"> <span class="keyword">int</span> y, z, nex;</span><br><span class="line">} e[maxn];</span><br><span class="line"><span class="keyword">int</span> head[maxn], tot = <span class="number">1</span>, hd[maxn];</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> z)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> e[++tot] = {y, z, head[x]};</span><br><span class="line"> head[x] = tot;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> s, t;</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">bfs</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>(d, <span class="number">0</span>, <span class="built_in"><span class="keyword">sizeof</span></span>(d));</span><br><span class="line"> queue<<span class="keyword">int</span>> q;</span><br><span class="line"> q.<span class="built_in">push</span>(s);</span><br><span class="line"> d[s] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (!q.<span class="built_in">empty</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x = q.<span class="built_in">front</span>();</span><br><span class="line"> q.<span class="built_in">pop</span>();</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = head[x]; i; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (!d[v] && e[i].z)</span><br><span class="line"> {</span><br><span class="line"> d[v] = d[x] + <span class="number">1</span>;</span><br><span class="line"> q.<span class="built_in">push</span>(v);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> d[t];</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">dfs</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> in)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (x == t || !in)</span><br><span class="line"> <span class="keyword">return</span> in;</span><br><span class="line"> <span class="keyword">int</span> out = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> &i = hd[x]; i && in; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (d[v] != d[x] + <span class="number">1</span> || !e[i].z)</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">int</span> res = <span class="built_in">dfs</span>(v, <span class="built_in">min</span>(in, e[i].z));</span><br><span class="line"> out += res;</span><br><span class="line"> in -= res;</span><br><span class="line"> e[i].z -= res;</span><br><span class="line"> e[i ^ <span class="number">1</span>].z += res;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> out;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> ans;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dinic</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">bfs</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">memcpy</span>(hd, head, <span class="built_in"><span class="keyword">sizeof</span></span>(head));</span><br><span class="line"> ans += <span class="built_in">dfs</span>(s, maxx);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">signed</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"> ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line"> cin >> n;</span><br><span class="line"> <span class="keyword">if</span> (n == <span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> cout << <span class="number">1</span> << endl;</span><br><span class="line"> cout << <span class="number">1</span> << endl;</span><br><span class="line"> cout << <span class="number">1</span> << endl;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= n; i++)</span><br><span class="line"> cin >> a[i];</span><br><span class="line"> <span class="keyword">int</span> len = <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"> {</span><br><span class="line"> f[i] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = i - <span class="number">1</span>; j >= <span class="number">1</span>; j--)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (a[j] > a[i])</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">if</span> (f[j] + <span class="number">1</span> >= f[i])</span><br><span class="line"> {</span><br><span class="line"> f[i] = f[j] + <span class="number">1</span>;</span><br><span class="line"> <span class="built_in">add</span>(j + n, i, <span class="number">1</span>);</span><br><span class="line"> <span class="built_in">add</span>(i, j + n, <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> len = <span class="built_in">max</span>(len, f[i]);</span><br><span class="line"> }</span><br><span class="line"> s = n * <span class="number">2</span> + <span class="number">1</span>, t = n * <span class="number">2</span> + <span class="number">2</span>;</span><br><span class="line"> cout << len << endl;</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><br><span class="line"> <span class="built_in">add</span>(i, i + n, <span class="number">1</span>);</span><br><span class="line"> <span class="built_in">add</span>(i + n, i, <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">if</span> (f[i] == <span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">add</span>(s, i, <span class="number">1</span>);</span><br><span class="line"> <span class="built_in">add</span>(i, s, <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (f[i] == len)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">add</span>(i + n, t, <span class="number">1</span>);</span><br><span class="line"> <span class="built_in">add</span>(t, i + n, <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">dinic</span>();</span><br><span class="line"> cout << ans << endl;</span><br><span class="line"> <span class="built_in">add</span>(s, <span class="number">1</span>, maxx), <span class="built_in">add</span>(<span class="number">1</span>, s, <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">add</span>(<span class="number">1</span>, n + <span class="number">1</span>, maxx);</span><br><span class="line"> <span class="built_in">add</span>(n + <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">if</span> (f[n] == len)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">add</span>(n, n + n, maxx);</span><br><span class="line"> <span class="built_in">add</span>(n + n, n, <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">add</span>(n + n, t, maxx);</span><br><span class="line"> <span class="built_in">add</span>(t, n + n, <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">dinic</span>();</span><br><span class="line"> cout << ans << endl;</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>
<h2 id="P2754-家园-星际转移问题"><a href="#P2754-家园-星际转移问题" class="headerlink" title="P2754 家园/星际转移问题"></a>P2754 家园/星际转移问题</h2><p><a href="https://www.luogu.com.cn/problem/P2754">题目链接</a></p>
<p>并查集判断是否有解</p>
<p>这道题最好的方法是建一张分层图(经典套路之一)</p>
<p>分层图是什么意思呢?</p>
<p>就是我们以时间为轴,每一个时间点,,我们建n+2个点,上一个时间点是会对当前时间点有一定的影响的,那么就从上一个时间点想着一个时间点进行连边</p>
<p>回到这个题:这个题的要求是每一艘飞船都是有着自己的循环周期的,那么我们在两个不同的时间点连边的时候,就需要根据周期连边,容量为飞船的载客量</p>
<p>当然了,我们上一个时间点空间站是可能有人在的,那么,我们就让上一个时间点的人流到当前时间点也要建一条边,容量为正无穷。</p>
<p>源点向第一行第一个点连边,汇点和每一行的最后连边,容量为无穷大</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">2e4</span> + <span class="number">10</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> inf = <span class="number">1e18</span>;</span><br><span class="line"><span class="keyword">int</span> n, m, k;</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="class">{</span></span><br><span class="line"> <span class="keyword">int</span> y, z, nex;</span><br><span class="line">} e[maxn];</span><br><span class="line"><span class="keyword">int</span> head[maxn], tot = <span class="number">1</span>, hd[maxn];</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> z)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> e[++tot] = {y, z, head[x]};</span><br><span class="line"> head[x] = tot;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> s, t;</span><br><span class="line"><span class="keyword">int</span> sta[<span class="number">30</span>][maxn], h[maxn];</span><br><span class="line"><span class="keyword">int</span> d[maxn];</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">bfs</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>(d, <span class="number">0</span>, <span class="built_in"><span class="keyword">sizeof</span></span>(d));</span><br><span class="line"> d[s] = <span class="number">1</span>;</span><br><span class="line"> queue<<span class="keyword">int</span>> q;</span><br><span class="line"> q.<span class="built_in">push</span>(s);</span><br><span class="line"> <span class="keyword">while</span> (!q.<span class="built_in">empty</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x = q.<span class="built_in">front</span>();</span><br><span class="line"> q.<span class="built_in">pop</span>();</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = head[x]; i; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (e[i].z && !d[v])</span><br><span class="line"> {</span><br><span class="line"> d[v] = d[x] + <span class="number">1</span>;</span><br><span class="line"> q.<span class="built_in">push</span>(v);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> d[t];</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">dfs</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> in)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (x == t || !in)</span><br><span class="line"> <span class="keyword">return</span> in;</span><br><span class="line"> <span class="keyword">int</span> out = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> &i = hd[x]; i && in; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (!e[i].z || d[v] != d[x] + <span class="number">1</span>)</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">int</span> res = <span class="built_in">dfs</span>(v, <span class="built_in">min</span>(in, e[i].z));</span><br><span class="line"> out += res;</span><br><span class="line"> in -= res;</span><br><span class="line"> e[i].z -= res;</span><br><span class="line"> e[i ^ <span class="number">1</span>].z += res;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> out;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> ans;</span><br><span class="line"><span class="keyword">int</span> cnt;</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">dinic</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">bfs</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">memcpy</span>(hd, head, <span class="built_in"><span class="keyword">sizeof</span></span>(head));</span><br><span class="line"> ans += <span class="built_in">dfs</span>(s, inf);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> ans;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> r[maxn];</span><br><span class="line"><span class="keyword">int</span> fa[maxn];</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">find</span><span class="params">(<span class="keyword">int</span> x)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (x == fa[x])</span><br><span class="line"> <span class="keyword">return</span> x;</span><br><span class="line"> <span class="keyword">return</span> fa[x] = <span class="built_in">find</span>(fa[x]);</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">merge</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> x = <span class="built_in">find</span>(x);</span><br><span class="line"> y = <span class="built_in">find</span>(y);</span><br><span class="line"> fa[x] = y;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">signed</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"> cin >> n >> m >> k;</span><br><span class="line"> n += <span class="number">2</span>;</span><br><span class="line"> s = <span class="number">2e4</span> + <span class="number">1</span>, t = s + <span class="number">1</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"> fa[i] = i;</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><br><span class="line"> {</span><br><span class="line"> cin >> h[i] >> r[i];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">0</span>; j < r[i]; j++)</span><br><span class="line"> {</span><br><span class="line"> cin >> sta[i][j];</span><br><span class="line"> <span class="keyword">if</span> (sta[i][j] <= <span class="number">0</span>)</span><br><span class="line"> sta[i][j] += n;</span><br><span class="line"> <span class="built_in">merge</span>(sta[i][j], sta[i][<span class="number">0</span>]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">find</span>(n - <span class="number">1</span>) != <span class="built_in">find</span>(n))</span><br><span class="line"> {</span><br><span class="line"> cout << <span class="number">0</span> << endl;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// n->earth n-1->moon</span></span><br><span class="line"> <span class="built_in">add</span>(s, n, inf), <span class="built_in">add</span>(n, s, <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">add</span>(n - <span class="number">1</span>, t, inf), <span class="built_in">add</span>(t, n - <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">for</span> (cnt = <span class="number">1</span>;; cnt++)</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><br><span class="line"> {</span><br><span class="line"> <span class="built_in">add</span>(i + (cnt - <span class="number">1</span>) * n, i + cnt * n, inf), <span class="built_in">add</span>(i + cnt * n, i + (cnt - <span class="number">1</span>) * n, <span class="number">0</span>);</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 <= m; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">add</span>(sta[i][(cnt - <span class="number">1</span>) % r[i]] + (cnt - <span class="number">1</span>) * n, sta[i][cnt % r[i]] + cnt * n, h[i]);</span><br><span class="line"> <span class="built_in">add</span>(sta[i][cnt % r[i]] + cnt * n, sta[i][(cnt - <span class="number">1</span>) % r[i]] + (cnt - <span class="number">1</span>) * n, <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">add</span>(s, n * cnt + n, inf), <span class="built_in">add</span>(n + cnt * n, s, <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">add</span>(n * cnt - <span class="number">1</span> + n, t, inf), <span class="built_in">add</span>(t, n + n * cnt - <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">dinic</span>();</span><br><span class="line"> <span class="keyword">if</span> (ans >= k)</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> cout << cnt << endl;</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>
<h2 id="P2045-方格取数加强版"><a href="#P2045-方格取数加强版" class="headerlink" title="P2045 方格取数加强版"></a>P2045 方格取数加强版</h2><p><a href="https://www.luogu.com.cn/problem/P2045">题目链接</a></p>
<p>这道题还挺好的,拆点拓宽了一点思路</p>
<p>首先,我们还是要建出来这个网格图的,自己和相邻的点连边(细节看代码</p>
<p>连边之后我们会想到什么呢,方格走一次会有价值,但是走两次不会有价值,那么我们拆点</p>
<p>可是……拆点是限制流量啊</p>
<p>不不不……你错了,拆点的时候不只是可以限制流量</p>
<p>我们这道题将每一个网格进行拆点操作,拆完之后的点中间连两条边:一条容量为1,费用为边权,另一条容量为正无穷,费用为0</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> inf = <span class="number">0x3f3f3f3f3f3f3f3f</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">1e5</span>+<span class="number">10</span>;</span><br><span class="line"><span class="keyword">int</span> a[<span class="number">55</span>][<span class="number">55</span>];</span><br><span class="line"><span class="keyword">int</span> n, k;</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="class">{</span></span><br><span class="line"> <span class="keyword">int</span> y, z, w, nex;</span><br><span class="line">} e[maxn];</span><br><span class="line"><span class="keyword">int</span> head[maxn], tot=<span class="number">1</span>, hd[maxn];</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> z, <span class="keyword">int</span> w)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> e[++tot] = {y, z, w, head[x]};</span><br><span class="line"> head[x] = tot;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">pos1</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y)</span> </span>{ <span class="keyword">return</span> (x - <span class="number">1</span>) * n + y; }</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">pos2</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y)</span> </span>{ <span class="keyword">return</span> (x - <span class="number">1</span>) * n + y + n * n; }</span><br><span class="line"><span class="keyword">int</span> ans, cost;</span><br><span class="line"><span class="keyword">int</span> s, t;</span><br><span class="line"><span class="keyword">int</span> d[maxn], vis[maxn];</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">spfa</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>(vis, <span class="number">0</span>, <span class="built_in"><span class="keyword">sizeof</span></span>(vis));</span><br><span class="line"> <span class="built_in">memset</span>(d, <span class="number">0x3f</span>, <span class="built_in"><span class="keyword">sizeof</span></span>(d));</span><br><span class="line"> queue<<span class="keyword">int</span>> q;</span><br><span class="line"> d[s] = <span class="number">0</span>;</span><br><span class="line"> q.<span class="built_in">push</span>(s);</span><br><span class="line"> <span class="keyword">while</span> (!q.<span class="built_in">empty</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x = q.<span class="built_in">front</span>();</span><br><span class="line"> vis[x] = <span class="number">0</span>;</span><br><span class="line"> q.<span class="built_in">pop</span>();</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = head[x]; i; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (e[i].z && d[v] > d[x] + e[i].w)</span><br><span class="line"> {</span><br><span class="line"> d[v] = d[x] + e[i].w;</span><br><span class="line"> <span class="keyword">if</span> (!vis[v])</span><br><span class="line"> vis[v] = <span class="number">1</span>, q.<span class="built_in">push</span>(v);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> d[t] != inf;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">dfs</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> in)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (x == t || !in)</span><br><span class="line"> <span class="keyword">return</span> in;</span><br><span class="line"> <span class="keyword">int</span> out = <span class="number">0</span>;</span><br><span class="line"> vis[x] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> &i = hd[x]; i && in; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (!e[i].z || vis[v] || d[v] != d[x] + e[i].w)</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">int</span> res = <span class="built_in">dfs</span>(v, <span class="built_in">min</span>(in, e[i].z));</span><br><span class="line"> out += res;</span><br><span class="line"> in -= res;</span><br><span class="line"> e[i].z -= res;</span><br><span class="line"> e[i ^ <span class="number">1</span>].z += res;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> out;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dinic</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">spfa</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">memcpy</span>(hd, head, <span class="built_in"><span class="keyword">sizeof</span></span>(head));</span><br><span class="line"> <span class="keyword">int</span> res = <span class="built_in">dfs</span>(s, inf);</span><br><span class="line"> ans += res;</span><br><span class="line"> cost += res * d[t];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">signed</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"> ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line"> cin >> n >> k;</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">for</span> (<span class="keyword">int</span> j = <span class="number">1</span>; j <= n; j++)</span><br><span class="line"> cin >> a[i][j];</span><br><span class="line"> s = <span class="number">1</span>, t = n * n * <span class="number">2</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><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">1</span>; j <= n; j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">add</span>(<span class="built_in">pos1</span>(i, j), <span class="built_in">pos2</span>(i, j), <span class="number">1</span>, -a[i][j]);</span><br><span class="line"> <span class="built_in">add</span>(<span class="built_in">pos2</span>(i, j), <span class="built_in">pos1</span>(i, j), <span class="number">0</span>, a[i][j]);</span><br><span class="line"> <span class="built_in">add</span>(<span class="built_in">pos1</span>(i, j), <span class="built_in">pos2</span>(i, j), k - <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">add</span>(<span class="built_in">pos2</span>(i, j), <span class="built_in">pos1</span>(i, j), <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"> <span class="keyword">if</span> (j != n)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">add</span>(<span class="built_in">pos2</span>(i, j), <span class="built_in">pos1</span>(i, j + <span class="number">1</span>), inf, <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">add</span>(<span class="built_in">pos1</span>(i, j + <span class="number">1</span>), <span class="built_in">pos2</span>(i, j), <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (i != n)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">add</span>(<span class="built_in">pos2</span>(i, j), <span class="built_in">pos1</span>(i + <span class="number">1</span>, j), inf, <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">add</span>(<span class="built_in">pos1</span>(i + <span class="number">1</span>, j), <span class="built_in">pos2</span>(i, j), <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">dinic</span>();</span><br><span class="line"> cout << -cost << endl;</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>
<h2 id="P2053-修车"><a href="#P2053-修车" class="headerlink" title="P2053 修车"></a>P2053 修车</h2><p>又是一道分层图的网络流呢</p>
<p>不过这道题还是很妙的,把我和Cloudysky困住了一小会来着</p>
<p>首先我们以工人为横轴,阶段为纵轴进行分层图的构建:</p>
<p>我们可以知道的是:对于倒数第i位,他会对自己后面的i位造成时间上的等待,那么我们考虑倒着建分层图,建i个工人修的倒数j辆车</p>
<p>这个节点向n个车连边,然后n个车向汇点连边,容量为1,向车连边的费用为当前阶段乘上时间</p>
<p>然后,我们考虑分层图上建边:</p>
<p>当前工人连第一个人的阶段应该连无穷大的流量,当前阶段连向下一个阶段的边流量也一样是无穷大,费用是0</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">2e5</span> + <span class="number">10</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> inf = <span class="number">1e18</span>;</span><br><span class="line"><span class="keyword">int</span> n, m;</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="class">{</span></span><br><span class="line"> <span class="keyword">int</span> y, z, w, nex;</span><br><span class="line">} e[maxn * <span class="number">2</span>];</span><br><span class="line"><span class="keyword">int</span> head[maxn], tot = <span class="number">1</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> z, <span class="keyword">int</span> w)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> e[++tot] = {y, z, w, head[x]};</span><br><span class="line"> head[x] = tot;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> s, t;</span><br><span class="line"><span class="keyword">int</span> vis[maxn], d[maxn], hd[maxn];</span><br><span class="line"><span class="keyword">int</span> cost;</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">spfa</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>(d, <span class="number">0x3f</span>, <span class="built_in"><span class="keyword">sizeof</span></span>(d));</span><br><span class="line"> <span class="built_in">memset</span>(vis, <span class="number">0</span>, <span class="built_in"><span class="keyword">sizeof</span></span>(vis));</span><br><span class="line"> queue<<span class="keyword">int</span>> q;</span><br><span class="line"> d[s] = <span class="number">0</span>;</span><br><span class="line"> q.<span class="built_in">push</span>(s);</span><br><span class="line"> <span class="keyword">while</span> (!q.<span class="built_in">empty</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> x = q.<span class="built_in">front</span>();</span><br><span class="line"> q.<span class="built_in">pop</span>();</span><br><span class="line"> vis[x] = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = head[x]; i; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (e[i].z && d[v] > d[x] + e[i].w)</span><br><span class="line"> {</span><br><span class="line"> d[v] = d[x] + e[i].w;</span><br><span class="line"> <span class="keyword">if</span> (!vis[v])</span><br><span class="line"> vis[v] = <span class="number">1</span>, q.<span class="built_in">push</span>(v);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> d[t] != <span class="number">0x3f3f3f3f3f3f3f3f</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">dfs</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> in)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (x == t || !in)</span><br><span class="line"> <span class="keyword">return</span> in;</span><br><span class="line"> <span class="keyword">int</span> out = <span class="number">0</span>;</span><br><span class="line"> vis[x] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> &i = hd[x]; i && in; i = e[i].nex)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> v = e[i].y;</span><br><span class="line"> <span class="keyword">if</span> (vis[v] || !e[i].z || d[v] != d[x] + e[i].w)</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">int</span> res = <span class="built_in">dfs</span>(v, <span class="built_in">min</span>(in, e[i].z));</span><br><span class="line"> out += res;</span><br><span class="line"> in -= res;</span><br><span class="line"> e[i].z -= res;</span><br><span class="line"> e[i ^ <span class="number">1</span>].z += res;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> out;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">int</span> ans;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dinic</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">spfa</span>())</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">memcpy</span>(hd, head, <span class="built_in"><span class="keyword">sizeof</span></span>(head));</span><br><span class="line"> <span class="keyword">int</span> k = <span class="built_in">dfs</span>(s, <span class="number">1e18</span>);</span><br><span class="line"> ans += k;</span><br><span class="line"> cost += k * d[t];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">signed</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"> cin >> m >> n;</span><br><span class="line"> s = <span class="number">0</span>, t = <span class="number">2</span> * n * m + n + <span class="number">1</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><br><span class="line"> <span class="built_in">add</span>(s, i, inf, <span class="number">0</span>), <span class="built_in">add</span>(i, s, <span class="number">0</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">1</span>; i <= n; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">1</span>; j <= m; j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> T;</span><br><span class="line"> cin >> T;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k = <span class="number">0</span>; k < n; k++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">add</span>(k * m + j + n * m, n * m * <span class="number">2</span> + i, <span class="number">1</span>, T * (k + <span class="number">1</span>));</span><br><span class="line"> <span class="built_in">add</span>(n * m * <span class="number">2</span> + i, n * m + k * m + j, <span class="number">0</span>, -T * (k + <span class="number">1</span>));</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= m; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">1</span>; j < n; j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">add</span>(m * (j - <span class="number">1</span>) + i, m * j + i, inf, <span class="number">0</span>), <span class="built_in">add</span>(m * j + i, m * (j - <span class="number">1</span>) + i, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">1</span>; j <= n; j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">add</span>(i + m * (j - <span class="number">1</span>), i + m * (j - <span class="number">1</span> + n), <span class="number">1</span>, <span class="number">0</span>), <span class="built_in">add</span>(i + m * (j - <span class="number">1</span> + n), i + m * (j - <span class="number">1</span>), <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= n; i++)</span><br><span class="line"> <span class="built_in">add</span>(n * m * <span class="number">2</span> + i, t, <span class="number">1</span>, <span class="number">0</span>), <span class="built_in">add</span>(t, n * m * <span class="number">2</span> + i, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">dinic</span>();</span><br><span class="line"> <span class="keyword">double</span> mm = (<span class="keyword">double</span>)cost / n;</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%.2f"</span>, mm);</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>
<h1 id="就先写这一点点叭,以后还会有其他博客的哦-8971-个词,辛苦我了。"><a href="#就先写这一点点叭,以后还会有其他博客的哦-8971-个词,辛苦我了。" class="headerlink" title="就先写这一点点叭,以后还会有其他博客的哦 8971 个词,辛苦我了。"></a>就先写这一点点叭,以后还会有其他博客的哦 8971 个词,辛苦我了。</h1>]]></content>
<tags>
<tag>图</tag>
</tags>
</entry>
<entry>
<title>群论</title>
<url>/%E7%BE%A4%E8%AE%BA/</url>
<content><![CDATA[<h1 id="群论初步-学习笔记"><a href="#群论初步-学习笔记" class="headerlink" title="群论初步 学习笔记"></a>群论初步 学习笔记</h1><h2 id="群-定义"><a href="#群-定义" class="headerlink" title="群 定义"></a>群 定义</h2><p>一个集合被称为群当且仅当它满足以下四个条件:</p>
<ol>
<li><p>具有乘法封闭性,即:任意的$a,b\in G,a*b\in G$</p>
</li>
<li><p>具有结合律:$( a * b ) * c = a * ( b * c ) $,左右乘是两个不一样的定义</p>
</li>
<li><p>具有幺元e:对于任意的$a\in G$都有$e * a = a , a * e = a$还是,左右乘定义并不一样</p>
</li>
<li><p>具有逆元:即:对于任意的$a\in G$ 都存在一个inv使得$a * inv = e , inv *a = e$</p>
</li>
</ol>
<p>普通的以$*$代指</p>
<p>然而还有另外的就是:一个群并不一定满足交换律 ,但是存在着满足交换律的群,我们称之为Abel群运算符号以$+$代指,幺元记为0</p>
<ol start="5">
<li>子群:群G的子集H满足上述四条公理那我们们称之为群G的子群,因此:H$\le$G,并且幺元不变</li>
</ol>
<p>陪集分解:群G,子群H,$g\in G$,$gH$为左陪集,$Hg$为右陪集</p>
<p><strong>子群检验法</strong>(subgroup test)是群G的子集H是子群的充分必要条件:对于所有元素$g\in G,h\in H$只需检查$g^{-1}\cdot h\in H$ 。</p>
<p>引理:对于任意的$h\in H,g\in G~g\cdot H=g\cdot h\cdot H$</p>
<p>任意两个陪集aH,bH满足以下两个条件之一</p>
<ul>
<li>aH=bH</li>
<li>$aH\cap bH =\phi$ </li>
</ul>
<ol start="6">
<li><p>拉格朗日定理:对于任意的$g\in G |gH|=|H|,|H|整除于|G|$</p>
<p>一个群进行陪集分解之后得到的子群个数为$[G:H]$,称为H的指数</p>
<p>$|G|=[G:H]|H|$</p>
</li>
<li><p>对称群/置换群:对于一个集合,我们将其中的元素都用一个${1…|G|}$中的数映射,这些映射是会在复合意义下构成一个群的。记为$S_n$ 以$(a_1,a_2…a_n)$代指这个群中的元素,对称群的映射是可以构成若干个并不会相交的环的叫做轮换</p>
</li>
<li><p>群作用:群G和集合X,G*X表示任意的$g\in G~x\in X$二元组$(g,x)$构成G和X的笛卡尔积。是满足结合律的,</p>
<p>满足两个条件:$ 1_G * x = x , \forall x \in X$,$ g_1 * ( g_2 * x ) = ( g_1 * g_2 ) * x, \forall g_1 , g_2 \in G,x \in X$</p>
<p>几个例子:</p>
<ul>
<li><p> ⽐如$S_n ↷ {1,2, ⋯ , ;}$。 </p>
</li>
<li><p>再⽐如$G ↷ G$,G对⾃⾝的左乘作⽤。</p>
</li>
<li><p>再⽐如$D_n ↷ {ํ有标号的正n边形}$。</p>
</li>
<li><p>设L为有标号的正四⾯体,则有:</p>
</li>
<li><ul>
<li>$Isom^+(T)↷ T$; </li>
</ul>
</li>
<li><ul>
<li>$Isom(T)↷T$ ;</li>
</ul>
</li>
</ul>
</li>
<li><p>轨道:首先我们定义一个二元关系:$x-y$(不是减号)就相当于是$\exists g\in G ~gx=y$。这个二元关系显然是一个等价关系(两边同乘逆元),这二元关系一定要满足某一些性质就比如: </p>
<ul>
<li><p>这个二元关系要满足自自相关 </p>
</li>
<li><p>$A-B,B-A$两个是需要相互满足的 </p>
</li>
<li><p>$A-B,B-C那么C-B$,传递性。那么轨道就是指这个二元关系传递下去之后所形成的一个类似于等价类的东西</p>
<p> 所以x所在的等价类记为$G_x = O_x = {ax|a ∈ G}$,称为x的轨道</p>
<p>若X只有一个G轨道,则称G在X上的作用传递或可迁</p>
</li>
<li><p>稳定化子:$G_x=Stab_G(x)=(a\in G:ax=x)$成为x的稳定化子,易见Stab(x)是G的一个子群.</p>
<ol>
<li><p><strong>幺元</strong>必定在其中</p>
</li>
<li><p>$ a , b \in Stab_G ( x ) , a * b \in Stab_G ( x ) $。所以<strong>乘法封闭</strong></p>
</li>
<li><p>$1 * x = x , g ^ { -1 } * g * x = g ^ { -1 } x$所以<strong>逆元</strong>也在</p>
<p>证毕</p>
</li>
</ol>
</li>
</ul>
<p>引理:$\forall x\in X,g\in G,Stab_g(gx)=gStab_G(x)g^{-1}$</p>
</li>
<li><p>轨道-稳定化子定理:现设有群作用$G↷X$,则$|O_x|=[G:Stab_G(x)]$,进而有$|G|=|Stab_G(x)||O_x|$</p>
<p>证明:</p>
<p>设$H=Stab_G(x)<=G$那么我们做G的H-陪集分解:</p>
<p>$G=a_1H\bigcup a_2H\bigcup a_3H\bigcup…\bigcup a_kH$</p>
<p>则:$O_x=a_1Hx\bigcup a_2Hx\bigcup a_3Hx\bigcup…\bigcup a_kHx={a_1x,a_2x,a_3x,…,a_kH}$</p>
<p>故:$|O_x|=k=[G:H]=[G:Stab_G(x)]$</p>
<p>由$|G|=|Stab_G(x)|[G:Stab_G(x)]$有$|G|=|O_x||Stab_G(x)|$</p>
</li>
</ol>
<h2 id="Burnside’s-Lemma"><a href="#Burnside’s-Lemma" class="headerlink" title="Burnside’s Lemma"></a>Burnside’s Lemma</h2><blockquote>
<p>定义:设有群作用$G↷ X$ ,则X内的G-轨道数为G中元素的平均不动点个数,即:$\frac{1}{|G|}\sum_{g\in G}|X^g|$,其中,$X^g$表示X在g下的不动点,即:{$x\in X:gx=x$}</p>
</blockquote>
<p>例子:现在有个正6边形,需要给每个顶点着⾊,问在旋转同构意义下有多少本质不同的着⾊⽅案。</p>
<p>我们明确一下我们的群:{$0,60, 120,180, 240, 300$}(由于我不会加单位</p>
<p>所有的染色方法应该是$2^6$,在旋转$60$度的时候应该有一个轨道,就是两种染色方案,120的时候两个轨道,180时3个,240时2个,300时1个,所以总共应该是$\frac{64+2+4+8+4+2}{6}=14$种</p>
<h2 id="Polya’s-theorem"><a href="#Polya’s-theorem" class="headerlink" title="Pólya’s theorem"></a>Pólya’s theorem</h2><p>具体⽽⾔, $G\le S_n$对于G ↷ {1,2, ⋯ , ;}并且给{1,2, ⋯ , ;}着⾊这种问题,假设颜⾊数为c,则对⼀个排列{$a_i$}来说,记它的轮换个数为k,则它的不动点个数为$c^k$)。 </p>
<p>事实上,任意⼀个⼤⼩为n的群都同构于$s_n$的⼀个⼦群。(Cayley定理,考虑左乘作⽤)。</p>
]]></content>
<tags>
<tag>数学</tag>
</tags>
</entry>
<entry>
<title>后缀数组基础</title>
<url>/%E5%90%8E%E7%BC%80%E6%95%B0%E7%BB%84%E5%9F%BA%E7%A1%80/</url>
<content><![CDATA[<p>终于来了……</p>
<h1 id="一车的定义来了"><a href="#一车的定义来了" class="headerlink" title="一车的定义来了"></a>一车的定义来了</h1><ul>
<li><p>记字符串为$s[1,n]$,则我们称从𝑖开始的后缀为$s[i,n]$。</p>
</li>
<li><p>我们称所有后缀为集合$s[1,n],s[2,n],…,s[n,n]$。</p>
</li>
<li><p>对该集合排序时按照字典序排序,这样可以得到一个“后缀”数组。</p>
</li>
<li><p>$Rank[i]$表示从𝑖开始的后缀在排序后的的数组中的排名(升序)</p>
</li>
<li><p>$sa[i]$表示排名为i的后缀的首字符的位置(即从$sa[i]$开始的后缀</p>
</li>
<li><ul>
<li>容易发现$Rank[sa[i]]=i$</li>
</ul>
</li>
<li><p>$height[i]$表示排名为i的后缀和排名为i-1的后缀LCP(最长公共前缀)的长度</p>
</li>
</ul>
<h1 id="倍增算法"><a href="#倍增算法" class="headerlink" title="倍增算法"></a>倍增算法</h1><p>(倍增算法用的最广泛并且最短,有线性做法但是很难用(不如直接SAM</p>
<p>具体而言,我们分轮数进行后缀数组的构建:</p>
<p>在第i轮的时候,我们把每一个后缀的前$2^{i+1}$位进行排序(不够就直接排序就可以,按照以字典序为0的字符插进去一样的改</p>
<p>在倍增的过程中我们需要用到基数排序:</p>
<p>我们如果要求这一路的话我们应该是已经把上一轮求过了,就是说前面一半字符的排名都已经求过了</p>
<p>那么我们可以把前面板部分缩成一个数字</p>
<p>那么:后半部分……其实是可以进行转化的:</p>
<p>如果说一个字符串有当前的后半部分的话,那么这个后半部分应该是拎一个后缀的前缀,就是当前$i+2^k$位置后缀的前缀</p>
<p>那么我们也可以把后半部分转化成一个数字来进行排序</p>
<p>那么说明当前我们把所有的后缀转化成了一个双关键字排序</p>
<p>那么我们就先按照后半部分进行一次排序(因为第一关键字已经排过序了</p>
<p>那么因为基数排序是稳定的所以我们并不需要担心第一关键字的顺序变混乱</p>
<p><strong>上面是求得sa数组的算法</strong></p>
<p>height数组是有一个性质的:$height[Rank[i]]>=height[Rank[i-1]]+1$(我不想证明了背过结论就可以了</p>
<p>然后就可以线性的求height数组了</p>
<p><strong>我觉得下面代码的注释还挺详细的</strong></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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">1e6</span> + <span class="number">10</span>;</span><br><span class="line"><span class="keyword">int</span> n, sa[maxn], x[maxn], y[maxn], rk[maxn], height[maxn], m, c[maxn];</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">sa:排名为i的是哪一个后缀</span></span><br><span class="line"><span class="comment">x:第一关键字</span></span><br><span class="line"><span class="comment">y:第二关键字</span></span><br><span class="line"><span class="comment">rk:第i个后缀的排名</span></span><br><span class="line"><span class="comment">height:排名第i的后缀和排名第i-1的后缀的LCP</span></span><br><span class="line"><span class="comment">c:基数排序的时候所要用到的桶</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">char</span> s[maxn];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">get_sa</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <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"> ++c[x[i] = s[i]]; <span class="comment">//将每一个数放在我们的桶里</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">2</span>; i <= m; i++)</span><br><span class="line"> c[i] += c[i - <span class="number">1</span>]; <span class="comment">//前缀和,基数排序的时候要用到</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = n; i; i--)</span><br><span class="line"> sa[c[x[i]]--] = i; <span class="comment">//基数排序</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k = <span class="number">1</span>; k <= n; k <<= <span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> num = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = n - k + <span class="number">1</span>; i <= n; i++)</span><br><span class="line"> y[++num] = i; <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> (sa[i] > k)</span><br><span class="line"> y[++num] = sa[i] - k; <span class="comment">//按照sa的顺序把后缀插进去</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><br><span class="line"> c[i] = <span class="number">0</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"> c[x[i]]++; <span class="comment">//桶++</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">2</span>; i <= m; i++)</span><br><span class="line"> c[i] += c[i - <span class="number">1</span>]; <span class="comment">//前缀和</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = n; i; i--)</span><br><span class="line"> sa[c[x[y[i]]]--] = y[i], y[i] = <span class="number">0</span>; <span class="comment">//基数排序,按照第二关键字的顺序进行排序就可以保证我们的第一关键字相同的时候第二关键字小的在前面</span></span><br><span class="line"> <span class="built_in">swap</span>(x, y); <span class="comment">//因为我们当前的y已经没用了,所以我们直接把x和y进行交换就可以不用再写一个循环清空x了</span></span><br><span class="line"> num = <span class="number">1</span>;</span><br><span class="line"> x[sa[<span class="number">1</span>]] = <span class="number">1</span>; <span class="comment">//先把顺序在第一个的处理</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">2</span>; i <= n; i++)</span><br><span class="line"> x[sa[i]] = (y[sa[i]] == y[sa[i - <span class="number">1</span>]] && y[sa[i] + k] == y[sa[i - <span class="number">1</span>] + k]) ? num : ++num;</span><br><span class="line"> <span class="comment">//如果这个后缀的两个关键字都是一样的那么不需要更新我们的rk</span></span><br><span class="line"> <span class="keyword">if</span> (num == n) <span class="comment">//如果我们的num已经是n了说明我们已经更新了n次,那么说明我们所有的后缀应该都到了自己应该在的地方就不需要进行多余的循环了</span></span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> m = num; <span class="comment">//如果并没有结束我们的循环的话我们就还需要进行循环,那么我们就可以将我们的m更新为现在还有多少个不相同的后缀,那么我们下一次的m就可以直接更新为不相同的数目。但是亲测m=n也是可以过的(似乎没有人会去卡这个东西</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">get_height</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></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"> rk[sa[i]] = i; <span class="comment">//排名是i的字符串的排名是i(废话</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>, k = <span class="number">0</span>; i <= n; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (rk[i] == <span class="number">1</span>) <span class="comment">// height[1]=0</span></span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">if</span> (k)</span><br><span class="line"> --k;</span><br><span class="line"> <span class="comment">//性质:height[rk[i]]>=height[rk[i]-1]-1</span></span><br><span class="line"> <span class="keyword">int</span> j = sa[rk[i] - <span class="number">1</span>]; <span class="comment">//排名是rk[i]-1的后缀</span></span><br><span class="line"> <span class="keyword">while</span> (i + k <= n && j + k <= n && s[i + k] == s[j + k])</span><br><span class="line"> k++; <span class="comment">//暴力向后匹配</span></span><br><span class="line"> height[rk[i]] = k; <span class="comment">//更新</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">signed</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"> ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line"> cin >> s + <span class="number">1</span>;</span><br><span class="line"> n = <span class="built_in">strlen</span>(s + <span class="number">1</span>);</span><br><span class="line"> m = <span class="number">122</span>;</span><br><span class="line"> <span class="built_in">get_sa</span>();</span><br><span class="line"> <span class="built_in">get_height</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"> cout << sa[i] << <span class="string">' '</span>;</span><br><span class="line"> cout << endl;</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"> cout << height[i] << <span class="string">' '</span>;</span><br><span class="line"> cout << endl;</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>
<h1 id="例题"><a href="#例题" class="headerlink" title="例题"></a>例题</h1><h2 id="P4051-JSOI2007-字符加密"><a href="#P4051-JSOI2007-字符加密" class="headerlink" title="P4051 [JSOI2007]字符加密"></a>P4051 [JSOI2007]字符加密</h2><p><a href="https://www.luogu.com.cn/problem/P4051">题目链接</a></p>
<p>板子题……</p>
<p>我们对于一个环来说最好的解决方法是什么呢?</p>
<p>向后拓展一倍嘛</p>
<p>向后拓展一倍之后,再接着进行一次后缀数组的求解,如果我们求出来了后缀数组的排名,其实也就相当于是求出来了原来循环重构的排名</p>
<p>因为字典序他是从前向后考虑的,如果前面就已经不一样了,那么后面就可以不用考虑了,就算是考虑到了也没有什么关系的,因为那证明了前面n位是一样的,那么其实随便输出任何一个就可以了(或者说他们的顺序就没什么考虑性了</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">2e5</span> + <span class="number">10</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> n, m;</span><br><span class="line"><span class="keyword">char</span> s[maxn];</span><br><span class="line"><span class="keyword">int</span> sa[maxn], rk[maxn];</span><br><span class="line"><span class="keyword">int</span> x[maxn], y[maxn];</span><br><span class="line"><span class="keyword">int</span> c[maxn];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">get_sa</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></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"> ++c[x[i] = s[i]];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">2</span>; i <= m; i++)</span><br><span class="line"> c[i] += c[i - <span class="number">1</span>];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = n; i; i--)</span><br><span class="line"> sa[c[x[i]]--] = i;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k = <span class="number">1</span>; k <= n; k <<= <span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> num = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = n - k + <span class="number">1</span>; i <= n; i++)</span><br><span class="line"> y[++num] = i;</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> (sa[i] > k)</span><br><span class="line"> y[++num] = sa[i] - k;</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><br><span class="line"> c[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 <= n; i++)</span><br><span class="line"> c[x[i]]++;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">2</span>; i <= m; i++)</span><br><span class="line"> c[i] += c[i - <span class="number">1</span>];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = n; i >= <span class="number">1</span>; i--)</span><br><span class="line"> sa[c[x[y[i]]]--] = y[i], y[i] = <span class="number">0</span>;</span><br><span class="line"> <span class="built_in">swap</span>(x, y);</span><br><span class="line"> num = <span class="number">1</span>;</span><br><span class="line"> x[sa[<span class="number">1</span>]] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">2</span>; i <= n; i++)</span><br><span class="line"> x[sa[i]] = (y[sa[i]] == y[sa[i - <span class="number">1</span>]] && y[sa[i] + k] == y[sa[i - <span class="number">1</span>] + k]) ? num : ++num;</span><br><span class="line"> <span class="keyword">if</span> (num == n)</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> m = num;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">signed</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"> ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line"> cin >> s + <span class="number">1</span>;</span><br><span class="line"> n = <span class="built_in">strlen</span>(s + <span class="number">1</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"> s[i + n] = s[i];</span><br><span class="line"> n *= <span class="number">2</span>;</span><br><span class="line"> m = <span class="number">122</span>;</span><br><span class="line"> <span class="built_in">get_sa</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><br><span class="line"> <span class="keyword">if</span> (sa[i] > (n / <span class="number">2</span>) + <span class="number">1</span> || sa[i] == <span class="number">1</span>)</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> cout << s[sa[i] - <span class="number">1</span>];</span><br><span class="line"> }</span><br><span class="line"> cout << endl;</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>
<h2 id="P4248-AHOI2013-差异"><a href="#P4248-AHOI2013-差异" class="headerlink" title="P4248 [AHOI2013]差异"></a>P4248 [AHOI2013]差异</h2><p><a href="https://www.luogu.com.cn/problem/P4248">题目链接</a><br>这个题为什么我加了快读之后变慢了我不理解</p>
<p>(我所做过的单调栈的第一道题</p>
<p>首先题目中的那个公式</p>
<p>前边一部分是可以提出来的</p>
<p>所以直接搞后半部分就可以了</p>
<p>后半部分就是一个单调栈的板子题了</p>
<p>求出来height数组</p>
<p>看一下每一个height数组都可以拓展到那一位就可以了</p>
<p>不过似乎ST表加上二分也是可以的</p>
<p>但是显然O(N)更优吧</p>
<p>所以还是单调栈比较好</p>
<p>不过这个题我是抄的题解</p>
<p>这篇题解整得特别妙啊</p>
<p>在搞单调栈的时候首先先来了一下找最左端比他自己小的</p>
<p>如果实在这个最左端的左边的话就可以进行继承了</p>
<p>因为j+1-i之间的h[i]一定是不能够进行更新的,一定是在j左边的点为答案</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">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">int</span> n, m;</span><br><span class="line"><span class="keyword">int</span> rk[maxn], sa[maxn];</span><br><span class="line"><span class="keyword">int</span> x[maxn], y[maxn], c[maxn], h[maxn];</span><br><span class="line"><span class="keyword">int</span> sta[maxn], cnt, pos[maxn];</span><br><span class="line"><span class="keyword">int</span> pre[maxn], lst[maxn];</span><br><span class="line"><span class="keyword">char</span> s[maxn];</span><br><span class="line"><span class="keyword">int</span> f[maxn];</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> IO</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">template</span> <<span class="keyword">typename</span> T></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">read</span><span class="params">(T &x)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> x = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">bool</span> f = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">char</span> c = <span class="built_in">getchar</span>();</span><br><span class="line"> <span class="keyword">while</span> (!<span class="built_in">isdigit</span>(c))</span><br><span class="line"> f |= c == <span class="string">'-'</span>, c = <span class="built_in">getchar</span>();</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">isdigit</span>(c))</span><br><span class="line"> x = x * <span class="number">10</span> + c - <span class="string">'0'</span>, c = <span class="built_in">getchar</span>();</span><br><span class="line"> <span class="keyword">if</span> (f)</span><br><span class="line"> x = -x;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span> <<span class="keyword">typename</span> T, <span class="keyword">typename</span>... Args></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">read</span><span class="params">(T &x, Args &...args)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="built_in">read</span>(x), <span class="built_in">read</span>(args...);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">template</span> <<span class="keyword">typename</span> T></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">write</span><span class="params">(T x)</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">if</span> (x < <span class="number">0</span>)</span><br><span class="line"> <span class="built_in">putchar</span>(<span class="string">'-'</span>), x = -x;</span><br><span class="line"> <span class="keyword">if</span> (x > <span class="number">9</span>)</span><br><span class="line"> <span class="built_in">write</span>(x / <span class="number">10</span>);</span><br><span class="line"> <span class="built_in">putchar</span>(<span class="string">'0'</span> + x % <span class="number">10</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> IO;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">get_sa</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></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"> ++c[x[i] = s[i]];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">2</span>; i <= m; i++)</span><br><span class="line"> c[i] += c[i - <span class="number">1</span>];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = n; i; i--)</span><br><span class="line"> sa[c[x[i]]--] = i;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k = <span class="number">1</span>; k <= n; k <<= <span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> num = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = n - k + <span class="number">1</span>; i <= n; i++)</span><br><span class="line"> y[++num] = i;</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> (sa[i] > k)</span><br><span class="line"> y[++num] = sa[i] - k;</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><br><span class="line"> c[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 <= n; i++)</span><br><span class="line"> c[x[i]]++;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">2</span>; i <= m; i++)</span><br><span class="line"> c[i] += c[i - <span class="number">1</span>];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = n; i; i--)</span><br><span class="line"> sa[c[x[y[i]]]--] = y[i], y[i] = <span class="number">0</span>;</span><br><span class="line"> <span class="built_in">swap</span>(x, y);</span><br><span class="line"> num = <span class="number">1</span>;</span><br><span class="line"> x[sa[<span class="number">1</span>]] = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">2</span>; i <= n; i++)</span><br><span class="line"> x[sa[i]] = (y[sa[i]] == y[sa[i - <span class="number">1</span>]] && y[sa[i] + k] == y[sa[i - <span class="number">1</span>] + k]) ? num : ++num;</span><br><span class="line"> <span class="keyword">if</span> (num == n)</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> m = num;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">get_height</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></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"> rk[sa[i]] = i;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>, k = <span class="number">0</span>; i <= n; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (rk[i] == <span class="number">1</span>)</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">if</span> (k)</span><br><span class="line"> --k;</span><br><span class="line"> <span class="keyword">int</span> j = sa[rk[i] - <span class="number">1</span>];</span><br><span class="line"> <span class="keyword">while</span> (i + k <= n && j + k <= n && s[i + k] == s[j + k])</span><br><span class="line"> k++;</span><br><span class="line"> h[rk[i]] = k;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">signed</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>);</span><br><span class="line"> n = <span class="built_in">strlen</span>(s + <span class="number">1</span>);</span><br><span class="line"> m = <span class="number">122</span>;</span><br><span class="line"> <span class="built_in">get_sa</span>();</span><br><span class="line"> <span class="built_in">get_height</span>();</span><br><span class="line"> <span class="keyword">int</span> ans = n * (n - <span class="number">1</span>) * (n + <span class="number">1</span>) / <span class="number">2</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><br><span class="line"> <span class="keyword">while</span> (cnt && h[i] < h[sta[cnt]])</span><br><span class="line"> cnt--;</span><br><span class="line"> <span class="keyword">int</span> j = sta[cnt];</span><br><span class="line"> f[i] = f[j] + (i - j) * h[i];</span><br><span class="line"> ans -= <span class="number">2</span> * f[i];</span><br><span class="line"> sta[++cnt] = i;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">write</span>(ans);</span><br><span class="line"> <span class="built_in">puts</span>(<span class="string">""</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>
<h2 id="P2178-NOI2015-品酒大会"><a href="#P2178-NOI2015-品酒大会" class="headerlink" title="P2178 [NOI2015] 品酒大会"></a>P2178 [NOI2015] 品酒大会</h2><p><a href="https://www.luogu.com.cn/problem/P2178">题目链接</a></p>
<p>听说Rainbow是某个人,Freda是他的npy</p>
<p>这个题我们把所有的lcp对应的几个后缀求出来,然后后缀和一下</p>
<p>首先如果说连续的几个lcp相同的是可以合并的</p>
<p>那么合并我们就可以用到并查集</p>
<p>并查集记录一下size和fa就可以</p>
<p>我么从大到小枚举</p>
<p>以为大的也可以给小的做出贡献</p>
<p>那么我们就可以把他们放到并查集里</p>
<p>每次并查集更新都算一次答案的改变值(就省得费时费力一个一个算了,继承一下</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"><bits/stdc++.h></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> int long long</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> pii pair<span class="meta-string"><int, int></span></span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> maxn = <span class="number">3e5</span> + <span class="number">10</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> inf = <span class="number">2e18</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> max1[maxn], max2[maxn], min1[maxn], min2[maxn];</span><br><span class="line"><span class="keyword">int</span> rk[maxn], sa[maxn], x[maxn], y[maxn], c[maxn], h[maxn];</span><br><span class="line">vector<<span class="keyword">int</span>> hs[maxn];</span><br><span class="line"><span class="keyword">int</span> n, m, fa[maxn], sz[maxn];</span><br><span class="line"><span class="keyword">int</span> v[maxn];</span><br><span class="line">pii ans[maxn];</span><br><span class="line"><span class="keyword">int</span> maxv = -inf, cnt = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">char</span> s[maxn];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">get_sa</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></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"> c[x[i] = s[i]]++;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">2</span>; i <= m; i++)</span><br><span class="line"> c[i] += c[i - <span class="number">1</span>];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = n; i; i--)</span><br><span class="line"> sa[c[x[i]]--] = i;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> k = <span class="number">1</span>; k <= n; k <<= <span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> num = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = n - k + <span class="number">1</span>; i <= n; i++)</span><br><span class="line"> y[++num] = i;</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> (sa[i] > k)</span><br><span class="line"> y[++num] = sa[i] - k;</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><br><span class="line"> c[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 <= n; i++)</span><br><span class="line"> c[x[i]]++;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">2</span>; i <= m; i++)</span><br><span class="line"> c[i] += c[i - <span class="number">1</span>];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = n; i; i--)</span><br><span class="line"> sa[c[x[y[i]]]--] = y[i], y[i] = <span class="number">0</span>;</span><br><span class="line"> <span class="built_in">swap</span>(x, y);</span><br><span class="line"> x[sa[<span class="number">1</span>]] = <span class="number">1</span>, num = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">2</span>; i <= n; i++)</span><br><span class="line"> x[sa[i]] = (y[sa[i]] == y[sa[i - <span class="number">1</span>]] && y[sa[i] + k] == y[sa[i - <span class="number">1</span>] + k]) ? num : ++num;</span><br><span class="line"> <span class="keyword">if</span> (num == n)</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> m = num;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">//求sa</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">get_height</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></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"> rk[sa[i]] = i;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>, k = <span class="number">0</span>; i <= n; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (rk[i] == <span class="number">1</span>)</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> <span class="keyword">if</span> (k)</span><br><span class="line"> k--;</span><br><span class="line"> <span class="keyword">int</span> j = sa[rk[i] - <span class="number">1</span>];</span><br><span class="line"> <span class="keyword">while</span> (i + k <= n && j + k <= n && s[i + k] == s[j + k])</span><br><span class="line"> k++;</span><br><span class="line"> h[rk[i]] = k;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">//求height</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">find</span><span class="params">(<span class="keyword">int</span> x)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (x == fa[x])</span><br><span class="line"> <span class="keyword">return</span> x;</span><br><span class="line"> <span class="keyword">return</span> fa[x] = <span class="built_in">find</span>(fa[x]);</span><br><span class="line">}</span><br><span class="line"><span class="comment">//并查集的find</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">merge</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> x = <span class="built_in">find</span>(x), y = <span class="built_in">find</span>(y);</span><br><span class="line"> fa[x] = y;</span><br><span class="line"> sz[y] += sz[x];</span><br><span class="line">}</span><br><span class="line"><span class="comment">//并查集的merge</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">C</span><span class="params">(<span class="keyword">int</span> x)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">return</span> x * (x - <span class="number">1</span>) / <span class="number">2</span>;</span><br><span class="line">}</span><br><span class="line"><span class="comment">//C n,2</span></span><br><span class="line"><span class="function">pii <span class="title">calc</span><span class="params">(<span class="keyword">int</span> r)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">auto</span> x : hs[r])</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> a = <span class="built_in">find</span>(x - <span class="number">1</span>), b = <span class="built_in">find</span>(x);<span class="comment">//把lcp是x的并起来</span></span><br><span class="line"> cnt -= <span class="built_in">C</span>(sz[a]) + <span class="built_in">C</span>(sz[b]);<span class="comment">//减去原来的贡献</span></span><br><span class="line"> <span class="built_in">merge</span>(a, b);</span><br><span class="line"> cnt += <span class="built_in">C</span>(sz[b]);<span class="comment">//加上现在的贡献</span></span><br><span class="line"> <span class="keyword">if</span> (max1[a] >= max1[b])</span><br><span class="line"> {</span><br><span class="line"> max2[b] = <span class="built_in">max</span>(max1[b], max2[a]);</span><br><span class="line"> max1[b] = max1[a];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (max1[a] > max2[b])</span><br><span class="line"> max2[b] = max1[a];</span><br><span class="line"> <span class="keyword">if</span> (min1[a] <= min1[b])</span><br><span class="line"> {</span><br><span class="line"> min2[b] = <span class="built_in">min</span>(min1[b], min2[a]);</span><br><span class="line"> min1[b] = min1[a];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (min1[a] < min2[b])</span><br><span class="line"> min2[b] = min1[a];</span><br><span class="line"> maxv = <span class="built_in">max</span>(maxv, <span class="built_in">max</span>(max1[b] * max2[b], min1[b] * min2[b]));</span><br><span class="line"> <span class="comment">//最大值可以从不同的情况下出现:1最大,2最大……</span></span><br><span class="line"> <span class="comment">//最后maxv也有不同种:原来的maxv,现在的最大乘次大,或者最小乘次小(负数的情况 </span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (maxv == -inf)</span><br><span class="line"> <span class="keyword">return</span> {cnt, <span class="number">0</span>};</span><br><span class="line"> <span class="keyword">return</span> {cnt, maxv};</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">signed</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"> ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line"> m = <span class="number">122</span>;</span><br><span class="line"> cin >> n;</span><br><span class="line"> cin >> s + <span class="number">1</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"> cin >> v[i];</span><br><span class="line"> <span class="built_in">get_sa</span>();</span><br><span class="line"> <span class="built_in">get_height</span>();</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">2</span>; i <= n; i++)</span><br><span class="line"> hs[h[i]].<span class="built_in">push_back</span>(i);</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><br><span class="line"> fa[i] = i;</span><br><span class="line"> sz[i] = <span class="number">1</span>;</span><br><span class="line"> max1[i] = min1[i] = v[sa[i]];</span><br><span class="line"> max2[i] = -inf, min2[i] = inf;</span><br><span class="line"> <span class="comment">//并查集的初始化</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = n - <span class="number">1</span>; i >= <span class="number">0</span>; i--)</span><br><span class="line"> ans[i] = <span class="built_in">calc</span>(i);</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><br><span class="line"> cout << ans[i].first << <span class="string">' '</span> << ans[i].second << endl;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"><span class="comment">//真是一道绝妙的题呢</span></span><br><span class="line"><span class="comment">//记得后缀和,有个小细节就是全局变量cnt</span></span><br><span class="line"><span class="comment">//还有maxv</span></span><br></pre></td></tr></table></figure>
<h2 id="P1117-NOI2016-优秀的拆分"><a href="#P1117-NOI2016-优秀的拆分" class="headerlink" title="P1117 [NOI2016] 优秀的拆分"></a>P1117 [NOI2016] 优秀的拆分</h2><p><a href="https://www.luogu.com.cn/problem/P1117">题目链接</a></p>
<p>这个题记录一下每一个端点开始的AA串和结尾的AA串然后乘起来就可以了</p>