forked from wizardcypress/MyAcmCodeTemplate
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path备忘录
executable file
·1606 lines (1233 loc) · 162 KB
/
备忘录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
训哥增栈大法之乾坤大挪移:
char * p = (char *) malloc(size) + size;
__asm("movl %0,%%esp\n" :: "r"(p));
2010.4.9
pku3714
求出两个点集之间的最小距离,可以借用最近点对的方法分治,把所有点先按x轴排序,然后分治做,
用另外的一个数组,通过利用递归分治的特点进行并归排序,按y排序,然后把这个数组的点按所属
点集分成两边,于是这两边的y都是有顺序的,然后对一边进行枚举,另外一边选择y位置和它前后相差14个
左右的点进行比较找最小的就可以了。
2010.4.15
pku2677 双调路径dp
给一个点集,从最左走两条互不相交的路线到最右点,求最小路径长度和。
f[i][j](i<j),表示从0到i和0到j这两条互不相交的路径的最短长度和,
当i!=j-1时:f[i][j]=min{f[k][j-1]+dis(p[k],p[j])}
否则:f[i][j]=f[i][j-1]+dis(p[j-1],p[j])
最后别忘了加上最后封口的那段距离。
2010.4.16
pku2431 贪心+堆
n个加油站,油箱无限,最少加油次数使得到达目的地。
对位置排序,从前往后一直走,直到没有油了就从之前的油站中选择最多的那个加上去。
pku2437 区间贪心
n个区间,用长为l的木板覆盖所有区间,求最少木板。
先按区间左边从小到大排,合并区间,然后从左向右能铺就铺。
pku1716 区间贪心
n个区间,找到一个最小的集合s,使得对于每一个区间,集合中至少有两个元素在这个区间中。
按照区间右边界从小到大排序,然后贪心的思想就是,在当前区间中,能往后放就往后放,这样后面的区间能和前面共享元素的几率会更大(在不改变当前集合元素个数情况下,选择最有利于子问题解的选择。)
PKU2287 DP
田忌赛马。
详见2006集训队黄劲松的论文
2010.4.17
pku1984 并查集
给出坐标点的相对位置,设计在线算法,回答任意点之间的曼哈顿距离。
可以用并查集做,专门设计一个RELA的关系结构,自动实现加减,表示两点之间的相对位置(写起来方便),然后路径压缩的时候通过加加减减来求出当前节点和代表点的关系即可。
pku1985 树的最长路,dp
f[i][0],f[i][1]分别表示以i为根的最长,次长路(必须经过i),然后第一次dfs求出所有儿子的f[x]的值,第二次dfs就考虑连同i的祖先,经过i的路径的最长长度。这里需要注意最长次长是否来自同一个儿子的问题。
2010.4.18
sicily 1859 turan图
给出n个点,加最多的边,使得不存在k阶完全子图。把n平摊分成k-1份,然后任意两分之间任意连边,这个边数可以证明是最多的。
sicily 1856 线段树
给出一棵树,然后q个询问,每个询问给出一条边,问原树去掉这条边后分成的两个子树各自最大最小点值的积的和。
把树进行先序遍历,然后在线段树中动态查找一棵子树的最大最小值,并且在先序序列中找出除这棵子树以外的地方的最大最小值便可。
2010.4.22
pku2110 二分+枚举下界+搜索判断
给出一个带权矩阵,从(1,1)走到(n,n),求出所有路径中点的权值的最大权减最小权最小的值。
二分这个差值,然后就可以枚举一个下界,就知道上界,从而可以用dfs直接去遍历一次来看是否可行。枚举下界的作用在于使得从起点到某一个点是否可能不依赖于具体的路径,而只要符合上下界就可以了,否则的话就要遍历所有的路径来判断是否可行,这样的话就会相当慢。
还有需要注意的是,dfs的时候记得要考虑起点和终点是否在界内。
pku3340 数位统计
水题,不说了。。。
2010.4.23
pku2303 dfs搜索
给出2n个玩具,分成2份,每份中都可以不断的套在一起。
搜索的一个优化思想在于,按照高度递减来做,然后搜一个的时候,顺便判断另外一个是否合法,这样速度就相当地快了。。。
2010.4.28
pku2157 2次dfs
在迷宫中找钥匙,然后开门,看是否可能达到目标。
2次dfs,第一次找钥匙,第二次开门,如果第二次都没有新的门可以开,那么就无解。
2010.4.30
pku3633 bfs
一个填充字符串的搜索题目,可以先预处理IN_S[i][j]表示t字符串的i到j是否可以由s复制所得,IN_T[i][j][k][l]表示t的k到l是否能由t的i到j复制所得,这样作判断的时候就相当的方便了。
然后就是位运算的bfs,0表示还没被填充,1表示已经填充,然后枚举空区间[i,j],接着分别看s和t[k][l]中是否存在区间可以填充[i,j],这里可以进行优化的是,如果大的空区间可以填充,那么它的子区间就不必考虑了。做的过程中注意判重。这样速度就相当快了~~(哥排第五~哈)。
pku2688 暴力 或者 dfs(tsp)
平面上有个机器人,有一些目标点,然后问机器人最少走多少部可以把所有目标点都遍历。
先预处理对于任意的目标点之间的最短距离,然后就是典型的tsp问题。这道 题目目标点太小,所以可以暴力枚举所有排列顺序,500ms就过了,不过也可以dfs,加上dling优化就因该会快很多。
pku2449 两点间的k短路
具体做法看网上,目前还未完全弄懂。
2010.5.14
pku 1704 博弈(转化为Staircase Nim)
一行n列的方格,m个位置不同的硬币,每次把硬币往左移动,不能跨过任何硬币,而且一个
格子只能放一枚硬币,求是否必胜。
其实可以转化为Staircase Nim问题,把相邻间的空格子数以及第一个硬币和左边界的
空格数作为一堆石子,然后每次的操作就相当于在当前这堆石子拿走一些,然后放到右边的那堆
石子,这就变成了Staircase Nim了,只要从右边起,把奇数的石子堆进行xor就可以了。
2010.5.15
pku3533 Nim积计算
记(X)为nim积运算符,计算a(X)b,先把a和b化成二进制,例如a=(2^d1+2^d2+..),然后
利用分配律,转化为求2^x(X)2^y的问题。接着对于2^x(X)2^y,考虑把x和y分别再化为二进制
形式,然后每一个数都是费马2-power数,利用桶排,从小到大做,把不同的数进行相乘,对于相同
的数,乘以3/2后再和其他数进行普通的nim积运算。
这里要写两个函数,一个是用于普通nim积的运算,另外一个是对于2^x的nim积运算。为了加快
速度,可以预先处理所有2^x(X)2^y的值,然后对于普通的nim积运算只需要完成分配律的运算即可。
还要注意的一点是,中途运算过程中,调用函数的值可能会超过题目要求,所以最好把范围改大点。
hdu3404 nim积运算
和上题一样。
2010.5.16
pku3710 树博弈
按照game theory中的fusion principle做就可以了,要注意一些特殊情况。
pku2975 nim计数
n堆石子,然后问如果必胜的话有多少种移动方法(一步)。
因为答案最多只有n,令ans=a1^a2^...^an,如果需要构造出异或值为0的数,
而且由于只能操作一堆石子,所以对于某堆石子ai,现在对于ans^ai,就是除了ai以外其他的石子
的异或值,如果ans^ai<=ai,那么对于ai的话,是可以减小到ans^ai的值,然后使得所有数
的异或值为0,也即转移到了必败态。
pku2960 sg函数
对于每一个堆,求出subtraction game的sg函数,然后进行异或就可以了。
pku1740 博弈分析
ltc的题,关键是要理解当所有堆都能是成对出现的时候是必败状态,并且如果不是所有堆
都成对出现的话是能够转移到所有堆都成对。
具体见网上解题报告.
2010.5.17
pku2425 sg函数
拓扑图上移动若干个棋子的博弈。直接sg之。要做个拓扑排序。
2010.5.20
hdu1255 求矩形面积交
扫描线,线段树记录覆盖一次的长度值,还有覆盖两次以上的长度值,这样更新的时候才能无误地更新.
2010.5.21
hdu1823 更新到点的二维线段树
更新到点的二维线段树,需要注意的两个地方是:
1.更新到点的时候,第一区间的祖先区间都要进行更新。
2.在更新第二区间时,因为对于该第二区间,所属的第一区间而言,
第二区间的一个格子是代表了实际的一行格子
所以更新时是需要进行更优判断的。
其实二维线段树上的所有点代表了二维平面上的所有可能的矩形,于是对某个点的改变,需要把所有包含
这个点的矩形进行更改,所以就有注意2的存在。
pku2155 查找到点的二维线段树
每次操作把一个矩形区域翻转,然后求某个点的情况。二维线段树,更新的时候只要把覆盖到的区间
直接覆盖,然后查找的时候要查找到底,把和这个点有关的所有矩形的覆盖次数都加起来,然后判奇偶就可以了。
注意查找返回时除了儿子的覆盖次数还要加上当前区间的覆盖次数。
2010.5.22
pku2185 二维的最小覆盖,kmp
先考虑一维的,那最小的周期就是n-pre[n],然后对于很多行而言,现在要取一个区间大小值,作为最小覆盖矩阵
的宽度,那么这个宽度取什么合适呢?我们只考虑一行的周期串,如果区间的大小值是周期的倍数的话,那么这个区间的前
后就能够衔接在一起,所以对于多行的情况就是求他们的lcm。对列的情况也一样。注意如果最后答案大于行列的范围就定
为行列范围。
2010.5.27
pku3261 后缀数组+二分+height数组判断
给出一个串,找出最长的重复至少k次的串。
先求出后缀数组和height数组,然后二分答案len,接着在height数组中以len为长度分组,然后看是否存在一组的
个数>=k就可以了。
pku1743 和3261做法类似
首先需要注意由于所谓“相等”的串很可能会有一个偏移值,所以需要对原来的字串进行转换,考虑如果两串之间是题目
所述的“相等”,那么他们相邻之间的差值一定是一样的,所以可以先把串相邻的相减得到新串,然后在新串上求出sa和height。
第二步是二分答案len,然后像上题一样进行分组,接着看每组中sa的最大和最小的差值是否大于(注意这里是大于
而不是大于等于,因为这是相邻差值,等于的话前后串就会有一个是相交的)len就可以了。最后答案要+1。
pku2774 求两个串的最长公共子串
把两串接在一起,中间加入一个从未出现的字符,最后添加一个特殊的最小字符。
求出sa和height,然后求出height的最大值,不过这里要求sa[i]和sa[i-1]在两个不同的串中。
spoj705 求不同字串个数
算法分析(摘自2009年集训队论文 罗穗骞):
“每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不 相
同的前缀的个数。如果所有的后缀按照 suffix(sa[1]), suffix(sa[2]),
suffix(sa[3]), …… ,suffix(sa[n]) 的顺序计算,不难发现,对于每一次新 加
进来的后缀 suffix(sa[k]), 它将产生 n-sa[k]+1 个新的前缀。但是其中有
height[k] 个是和前面的字符串的前缀是相同的。所以 suffix(sa[k]) 将 “ 贡献 ”
出 n-sa[k]+1- height[k] 个不同的子串。累加后便是原问题的答案。这个做法
的时间复杂度为 O(n) 。”
2010.5.28
spoj687 求重复次数最多的字串
求出sa和height后,建立rmq,然后枚举长度l,如果字串出现至少两次的话,在s[0],s[l],s[2*l]。。中必有
相邻两个是这个字串的开头两个周期,然后向后看能匹配多少,接着再看往前能否补齐一个周期,如果可以则重复次数+1,
最后由于匹配的时候跨了一个周期,最后答案+1。
2010.5.29
pku1041 求边字典序最小的欧拉回路
先判断是否是欧拉回路,然后把每个点的边的编号排序,然后就按照边从小到大遍历来找欧拉回路就可以了。。。
2010.5.30
pku1236 有向图加最少条边成为连通分量
先求scc,缩点,然后在DAG图中计算入度为0的点数,ind0,和出度为0的点数,od0,那么答案就是ind0和od0的
最大值。注意只有一个强连通分量的特殊处理.
pku2762 判断有向图的单向连通性
判断对于任意u,v是否存在u->v或者v->u的路径。先求scc缩点,然后进行拓扑排序,每次都要看当前可选节点是否
为1个,如果多于1个的话,那么这些节点就必定不能单向连通,所以就可以直接这样做。
pku3352,3177 无向图加最少边成为连通分量
首先需要知道的是,不同的low值表示是在不同的以桥为分界的分量里,而非书上所说的连通分量,不过这道题目照样
可以做,因为连通分量是针对删点的,也就是说在连通分量中任意删除一个点而能够连通。而这里只是说要删边,所以就可以
以桥为分界,把图通过low值分成多个分量,然后让度为1的点有cnt个,那么答案就是(cnt+1)/2.(叶子之间相互连接)
2010.6.1
pku2942 判断有多少个点不在任意一个奇圈内
先进行bcc,然后对于每一个bcc,如果存在一个奇圈,那么所有的点都能在一个奇圈内。而判断一个图是否存在奇圈,
可以进行黑白染色,如果能够黑白染色,那么就是二分图,就不可能存在奇圈,否则就存在奇圈。
2010.6.2
pku2723 二分+2-SAT
二分长度,然后判断2-sat图是否有解。2-sat问题一般都有这样的特点,有n对点,每对中选了一个,另外一个就不能
选,然后还有m个合取式,每个式都是形如X(v)Y的形式,(v)表示或关系,那么只需要对这m个合取式建图,对X(v)Y,
必有~X->Y和~Y->X,一个合取式建立两条边,然后求scc,判断在同一个scc中,是否~X和X同时存在,同时存在则无解。
pku2749 二分答案+根据二分值构图+2-SAT判断
详细见解题报告,关键是理解合取式的意义。
建立一堆形如(x v y)^(~x v y) ...等的合取式,然后对于单独的一个析取式x v y,添加边~x->y 和 ~y->x。
之后的工作就是判断在建立的这个有向图中是否存在矛盾。这里一般需要求解scc。
http://acm.pku.edu.cn/JudgeOnline/showcontest?contest_id=1177
pku3207 模型转化+2-SAT
n个点围成一圈,给出m对连线,那些线可以在圈内相连,也可以在圈外相连,问给出的线是否会相交。
对于每一个线,把它看成一个点,对于相交的线x,y,建立合取式(x v y)^(~x v ~y),也就是说,如果1表示在圈内,
0表示在圈外,那么这个合取式为真的情况只有两条先分别一个在圈内,一个在圈外。于是就对所有的线判断相交然后添加合取式,
最后判断是否矛盾就可以了。
2010.6.4
pku3678 2-SAT
这里只讲如何构图,其他的就直接模板水之。
x and y=0 ~x v ~ y //注意这里是析取式
x and y=1 ~x->x ~y->y //这里是直接建边,因为x,y都必须取1,所以~x->x这样按照反拓扑顺序就能够
//使得先染x和y。
x or y=0 x->~x y->~y
x or y=1 x v y
x xor y=0 (x v ~y)^(y v ~x)
x xor y=1 (x v y)^(~x v ~y)
pku1679 次小生成树
1.先求原图的最小生成树T,并记录树边和最小值small1
2.然后求dis[i][j],表示在T中x到y的唯一路径上的最大边
3.枚举所有非树边(u,v),设其值为w,那么small2=min{small1-dis[u][v]+w},最后看small1和
small2是否一样就可以了。
2010.6.6
pku2125 二分图最小点权覆盖
给一个有向图,可以进行两种操作,删除某个点的所有出度,代价为wo[i],或者删除某个点的所有入度,代价为
wi[i],问把所有边都删除最少的代价。
因为对于每一条边<u,v>,我们可以选择删除u的出度,或者v的入度,这就类似在二分图中,对应的一条边,然后我们选取代价最少的点,使得每一条边至少被其中一个点覆盖,这就是最小权点覆盖模型。
然后做法就是拆点,左边的点表示出度,源点对左边每一个点连一条容量为wo[i]的边,右边每个点向汇点连一条
wi[i]的边,然后对于边<u,v>,连一条oo容量的边。于是剩下的就是在这个图中求最大流,也就是最小割。那么这个最小割就对应了所选的删除入度和出度的情况。
还有一点要注意的是,平行边和自环都不能忽略,都要加到图中,因为这些边也是要计算到结果中的。
pku3469 最小割
n个模块,要么在第一个cpu上运行,代价Ai,要么在第二个cpu上运行,代价Bi,而且如果有一些模块对<u,v>如果在不同的cpu上运行会有额外代价wj,问把所有模块都运行的最小代价。
然后对于每个模块变为一个点,源点往每个模块连一条容量Ai的边,往汇点连Bi的边,然后对于<u,v>,连双向边,容量为w,求最大流便可。但至于为什么这样建图,为什么是最小割?目前还没有弄懂。
pku1815 枚举+最小割,最大流
对于每个点拆点成u,u',然后<u,u'>容量为1,对边<u,v>,建边<u',v>,<v',u>容量为inf,然后求最大流就可以了。不过由于题目需要输出所谓“字典序”最小,所以要从小到大枚举,然后先删除这个点,然后看最大流是否不变,如果不变的话,那么这个点就不是必须要删除的,否则就是个割,如果有变化的话,顺便修改最大流量,然后继续剩下的枚举。
2010.6.7
pku3422 最小费用流
给出n*n的矩阵,从1,1走到n,n,每走一个地方,就把那个地方清空,可以走k次(不是k步),问最多得到的权值和最大是多少。
矩阵中每个点拆成两个点,u,u',然后建边<u,u',1/-Aij>,<u,u',inf/0>,令v表示u的右边的点,w为u的下面的点,则有<u',v,inf/0>,<u',w,inf/0>,还有<st,1,k/0>,<n*n',ed,k/0>。
求最小费用流就可以了。
pku3680 最小费用流//最大k可重区间集问题
n个区间,每个区间都有权值。选出一些区间,使得任意位置上都不能有超过k个区间重叠,且权值最大。
一个很巧妙的构图方法:令离散点分别为a1,a2,...am,a0为源,am+1为汇,对任意0<=i<=m,建边
<ai,ai+1,k,0>,然后对于区间[x,y],找出x,y离散后的点ai,aj,然后添加边<ai,aj,1,-w>,w为该区间的权值。
求最小费用流就可以了。至于为什么这样。。。还在想。
后记:可以这样想,从左边到右边有一股水流过,流量限制为k,然后对于区间,所连的边相当于分流,使得在区间内的流量少于k,这样求最小费用流就能够符合条件了。
2010.6.8
pku3686 KM
n个工厂,生产m个产品,每个产品在不同工厂生产的时间不同,同一时间一个工厂只能生产一个产品,问生产所有产品的最小完成时间是多少。也即每个产品完成“时刻“的和最小。
这题首先就要想到和网络流,费用流,匹配之类的联系起来,对于这些有先后关系的情况,一般都是用拆点的方法来解决。先考虑对于某一个工厂来看,假如它生产的k个产品的时间为t1,t2,t3....tk,那么完成时间总和是k*t1+(k-1)*t2+(k-3)*t3+...+2*tk-1+tk,那么就可以这样建图,对于产品i和工厂j,如果i作为j的倒数第p个完成的产品,那么i的贡献时间为p*t[i][j],那么就从i连边到[jp],权值为-p*t[i][j]。
然后就在这样的图上用KM求最小权匹配就可以了。不过由于不明原因,这个图是n-n*m的,并不需要补点就可以过,现在还不明白为什么。
2010.6.10
sgu199 最长XX序列
要将数据有序化,先按s不减排,再按b不增排,然后对b做O(nlogn)的最长递增序列。注意,若i<j,要si<sj且bi<bj的时候才能符合所谓递增概念。第二个按不增排主要是让后面b更小的可以覆盖掉那些和它的s相同但是b更大的。
sgu153 sg+循环判断
初看是sg计算,不过由于p值相当小,所以从递推的式子可以看出,最多前2^Pmax个就会出现循环,用一个二进制记录当前点和前面Pmax个点的sg01情况,然后每次计算出当前点sg后就找是否有循环就可以了。
2010.6.11
codeforce round 17 D b^n*(b-1) %c
b^n*(b-1)%c=(b%c)^(n%phi(c)-1+phi(c)) * (b%c-1+c) %c;
由于对于n和c很小的时候,phi(c)有限制,所以对于strlen(n)<9也即n很小的时候直接算,不用phi(n),其余情况用该式。
2010.6.12
hdu3416 最大流
给出一个有向图和起点st,终点ed,然后假设st到ed的最短路为dis,那么问st到ed有多少条边不相交的长度为dis的路径数。
先求最短路,然后构图,对于边<u,v>,如果d[u]+w[u,v]==d[v],那么建边<u,v,1>,然后求个最大流就可以了。
思想不难,想想为什么这样。
2010.6.19
codeforce round 18 E dp
给出n*m的字符矩阵,然后对字符进行修改,使得1.每行最多两种不同颜色.2.相邻颜色不同。问最少修改次数,并输出方案。
令状态dp[i,a,b]表示前i行,而且第i行改为ababab..的矩阵的最少修改次数,由于题目限制,每行必定是两种颜色相间的,所以dp方程为:dp[i][a][b]=min{dp[i-1][j][k]}+Diff[i][a][b],j!=k && a!=b && a!=j && b!=k.
Diff[i][a][b]表示第i行改为ab相间需要修改的次数。这个方程还可以优化,由于j,k要符合j!=a && k!=b这个条件,然后这个条件是很稀疏的,所以可以记录上一行的最小值的位置p1,p2当a!=p1 && b!=p2时可以直接转移,否则就按照方程转移。时间复杂度为O(n*26^3)
codeforce round 17 C dp
详见此处:http://codeforces.com/blog/entry/451
2010.6.20
uva 10891 dp
给出n个数,a,b两个人每次从左或右取连续的若干个数,取完结束,求a最多比b大多少。
f[i][j]表示i到j先手最多可以取多少,那么转移方程为:
f[i][j]=max{sum[i,j]-f[i+k][j],sum[i][j]-f[i][j-k]} 1<=k<=j-i+1
2010.6.21
uva 11378 最近点对的变形
给出n个点,然后以每个点为中心构造一个正方形(和坐标平行),而且不能和其他点的正方形相交,问最大的边长是多少。
其实就是个最近点对的题目,分治,然后求出任意两点的x,y曼哈顿坐标最大的最小值。先把所有点按照x坐标排序,然后按照x坐标来划分,而且在分治做的时候顺便进行y坐标的并归排序。不过我这里犯的一个错误是,进行分界的时候取的点的x坐标是左右分治后的(l+r)/2上的点,但是在分治的时候,由于左边的[l,(l+r)/2]分治很可能已经把原来位于(l+r)/2上的点换了,所以作为划分的x坐标就不正确了,因此需要在分治前就记录划分的x位置。
2010.6.22
uva 10056 概率
n个人扔色子,每次扔到赢的概率为p,从1~n扔,如果还没有人扔到赢,那么从新从1开始扔。问第i个人赢的概率。
暴力模拟,sigma(p*(1-p)^(j*n+i-1)),j=0,1,2...oo, 只要j足够大达到精度就可以了。
uva 10491 概率
题目有点难解释,看原题吧。
主要解决方法是分情况,如果选手第一次选的是cow,那么得到car的概率是[cow/(cow+car)]*[car/(cow-1+show+car)],如果选的是car,那么得到car的概率是[car/(cow+car)]*[(car-1)/(cow-show+car-1)],加起来就是答案了。
2010.6.25
codeforce round 19 B
有n个商品,每个商品有价值ci和登记时间ti,销售员登记某样商品需要ti时间,在ti秒内可以偷ti件物品,问最少要付的钱来把n件商品清空。
一个牛人对此题的分析如下:
My thought process was something like this:
OK, this looks like DP or greedy. It's problem B so it might be greedy.
How should I sort items? Should I always pay for the cheapest item? No, doesn't work. Should I pay for the item with largest time? No. What about items with t=0.
Well, I guess it isn't greedy.
How would I write a recursive solution?
For each item I should either pay for it or steal it. If I pay for it then I can steal some other items. Yeah, state should definitely contain the position in sequence and the sum of ti.
Well I guess that's it, I just keep track of amount of items I have bought and the amount of items I can steal. In fact if I add 1 to each ti then it's even simpler.
That's it, more or less. It's hard to recall and describe exactly.
A lot of experience with DP and memoization helps ofcourse, but I think the best advice is to write or think about writing a simple recursive brute force solution and then figure what the state is.
When thinking about recursive solution you should try to make it as iterative as possible, that is scan elements in order and decide what to do with it.
排除了贪心的方法后,具体做法就是dp了。
状态就是dp[m][s]表示前m件物品,取出一些来付钱,使得sigma(ti+1)>=s 而且代价最少。
dp[m][s]=min{dp[m-1][s-t[m]-1]+c[m],dp[m-1][s]}
2010.7.3
pku1966 无向图的点连通度
对于有向图求边连通度,只需要固定一个源点,然后枚举汇点,求最小割的最小值就是边连通度了。固定源点的意思就在于对于把原图分割成不连通图的过程中,这个固定的源点必定在任意分割两点的一个之中,所以就可以固定一个而枚举汇点了。
对于无向图的点连通度,先拆点,u变为u',u'',建边<u',u'',1>,对(u,v),建边<u'',v',inf>,<v'',u',inf>.
源点取A'',汇点取B'。剩下做法和边连通度一样。
pku3189 二分或者枚举界+网络流
n只牛,b个牛棚,每只牛都有b个牛棚的喜好程度,然后求出把所有牛都放进牛棚中的最小喜好程度差。
枚举或者二分差值,然后再枚举下界,就知道上界了,接着就把超出这个界的边忽略掉求最大流,看是否满流。
2010.7.5
sgu269 dp
给出n个数,b1...bn,然后给出一个矩阵,第i行从左边到右边,左对齐有bi格是可放车的,而其他地方是不可放车的。而且这里的车是会对同行同列的其他车造成威胁,然后问在这样的矩阵中放置k个车有多少种方案。(注意车是可以跨越那些不能放车的空格进行攻击的)
首先考虑到,由于车可以跨“沟”攻击,所以其实bi的顺序对结果不造成影响,所以把bi按小到大排序,然后考虑使用递推来计算,一个容易想到的方法是f[n][k]表示前n行放k个车的方法数,以行为阶段划分,那么进而出现一个问题,对于列的重复如何进行判断?状态压缩?空间太大。增加决策状态?时间复杂度太高。其实陷入这个问题的关键是,我们一直对“选择了哪几个”而”耿耿于怀“,而没有想到我们只需要知道“选了多少个”和“当前能选多少个”就可以了,也就是说,之前选择了哪几个的顺序和位置信息对于决策无用处,我们只需要知道前n-1行选了多少个就可以了,这个可以在状态方程中知道,另外还要知道当前还能有多少种选择。由于bi从小到大排,所以就能很容易的知道当前还能选的个数,于是就有了以下的优美的状态转移方程。
f[n][k]=f[n-1][k-1]*(b[n]-(k-1)) //选
+f[n-1][k] //不选
这题要用到高精度。
sgu256 dp
N个人(N<=10)要吹M(M<=100)个气球,每个人只能够在一分钟之内操纵机器,吹出A[i]个气球,之后,就要休息至少B[i]分钟(1<=B[i]<=4),才能够再次操纵机器吹气球。问吹出这M个气球至少要多少分钟。
来自GHY神牛的思路:
由于题目给出的规模都很小,我们可以考虑到搜索。注意到休息的时间最多只有四分钟,因此可以使用一个5元组DP[m,p1,p2,p3,p4]表示:吹出m个气球,这1分钟吹的人是p4,前1分钟吹的人是p3,前2分钟吹的人是p2,前3分钟完的人是p4,p1,p2,p3,p4的取之范围是[0,n],为0则表示当前分钟没有人吹气球(大家都在休息)。那么可以得到转台转移方程:
DP[m,p1,p2,p3,p4]=min(DP[m-A[i],p2,p3,p4,i]),i从1遍历到n,若第i个人在此时不需要休息。
如果得不出答案,则DP[m,p1,p2,p3,p4]=DP[m,p2,p3,p4,0],相当于轮空1分钟。
另外,如果直接按照普通dp的话很可能会超时,而且这道题目有很多的无效状态,所以为了避免这些无效状态可以用记忆话dp来做,这样就能省去很多无效状态的枚举。
sgu223 压缩状态dp
给出n*n的棋盘,问放k个王有多少种方案。
由于王只对相邻的造成威胁,所以可以通过状态压缩的方法来进行递推计算,令f[i][j][state]表示前i行放j个王,而且第i行的状态为state的方案数,那么可以枚举i-1行的状态来进行递推,其余的就不详细了。
如果很裸的做的话会很慢,所以可以预先处理出一些合法的状态以及合法状态之间可以作为相邻的一些关系,然后可以发现这道题目的有效状态其实很少,所以可以用记忆化dp来做,可以省去很多无效状态。还有我在这里犯的一个错误是状态0和0是可以相通的,但是在添加状态关系的时候加了两次,导致错误,这里值得注意。
2010.7.22
pku 3764 xor 加 trie判断
给出一棵树,边有权,xor路径值为树路径上所有边的值异或的结果,问最大的xor路径值。
首先求出所有从根到点的xor值,然后就考虑在遍历树的过程中,对于每一个点,判断在之前遍历过的点中,和当前的值进行异或运算后值能达到最大的情况,这个可以通过对已经遍历了的点根据二进制构造一个trie树,然后从高位到低位,和当前的值进行逐位配对,看是否尽可能的做到每一位都尽量xor后为1,这样就能够找到和之前的点进行xor后得到的最大值。
2010.7.23
pku 3763 树dp
给出一棵树,然后问最少添加多少条边使得该图存在哈密顿回路。
一个重要的思想是,让最多的树边在这条回路上,那么也就相当于尽量利用原树边来构造尽量少的树路径。令f[x][0],f[x][1]分别表示x这个点和父亲在同一个路径和不在同一个路径上,而且构成一条链所需要的最少添加的边数。
对于f[x][0],最多只能和一个儿子相连,其余的都作为f[v][1]来连接,所以就有:
f[x][0]=min{f[x][0],f[v][0]+tot-f[v][1]+son[x]-1} 其中tot=sigma{f[v][1]},son[x]为x除父亲以外的邻接数。
对于f[x][1],考虑枚举两个儿子,使得他们经过x连成一条路径,其余的都以f[x][1]来连接,所以又有:
f[x][1]=min{f[x][1],f[a][0]+f[b][0]+tot-f[a][1]-f[b][1]+son[x]-2}
然而事实上是不许要对这两个儿子进行枚举的,因为对上面式子进行分析会发现只需要取f[a][0]-f[a][1]最小的两个就可以了,这个可以O(n)内完成。
然后f[x][1]=min{f[x][0],f[x][1]},因为不和父亲相连也可以像f[x][0]那样做。
最后答案是f[1][1]+1。
这里犯了一个错误,我取了一个全局数组aug,然后在递归的那个循环中对aug进行操作,后来才发现因为这个循环中有递归,所以在递归过程中会把该层中数组之前的一些值改变了。这里需要值得警醒,递归的时候如果需要用到全局变量,需要特别小心。
2010.7.25
pku3762 最大k可重区间集问题
有n个任务,每个任务有权值和运行的时间段,任务不能并行,给出k天,问最多可以达到多少权。
和pku3680一样,不过只是题目描述不同而已,可以把运行的时间段看成线段,而k就是最多k个区间可以相交,因为相交的线段可以分在k天中运行,而不相交的则没有关系。这就转化成了最大k可重区间集问题。
2010.7.28
codeforce24 D 暴力数学期望
n*m的格子,开始位置为i,j,只能向下,向左,向右走,或者停留原地问到达第n行的期望步数是多少。
从i,j到第n行的期望相当于从n行到i,j的期望,所以我们从下到上来做。
令e[i][j]表示第i,j的期望步数,那么迭代式为:
e[i][j]=1+sigma{e[i'][j']}/div; 其中div是sigma中的e[i'][j']的个数,而且由于sigma中也包括e[i][j]本身,所以把式子变换一下,得到:
sigma{e[i'][j']}
----------------
e[i][j]= (1+ div )
--------------------
1-1/div
然后暴力迭代直到达到某个精度为止。
zju2949 数学期望
有n碗A面条和n碗B面条,每次丢硬币决定吃哪种,直到只剩下一种为止,求丢硬币的次数。
考虑结束状态,吃了n个A面,i个B面,期望就是sigma{发生的步数*发生的概率},那么结果就是:
sigma{c[n+i-1][i]/2^(n+i)*(n+i)}
由于最后一碗肯定是A面,所以就是c[n+i-1][i],而且总状态是2^(n+i),一除就是概率,再乘以次数就是期望,这里考虑的是吃完A的,由对称性,还要乘以2才是结果。这里由于n很大,所以要注意计算精度,可以考虑用
e[i][j]=c[i][j]/2^j,并且e[i][j]=e[i-1][j]+e[i-1][j-1]/2。
另外一种解法,递推:
令f[i][j]表示AB面分别剩余i,j的期望值,那么f[i][0]=f[0][j]=0;
f[i][j]=f[i-1][j]/2+f[i][j-1]/2+1
输出f[n][n]即可。这个方法更加简单。
NOI2005 聪聪和可可 数学期望
给出一个图,有A和B在初始的位置,A要抓B,而且每次A先走,如果走一步后没有抓到B,则再走一步,而且每次都朝着更靠近B的路径的方向走,问A抓到B的期望步数。
求期望的题目大多都可以用递推做,如果递推中涉及到循环,一般先进行暴力,如果不涉及循环,那么就可以从终点开始进行递推,或者状态不好表示时可以用记忆化搜索,本题可以用递推的记忆化方法。
p[i][j]表示i到j的路径上,从i出发的第一个点的编号。w[j][k]表示j的第k个相邻的点。T[i]为i的度数。
x=p[p[i][j]][j]
那么f[i][j]=[sigma{f[x,w[j][k]]}+f[x][j]]/(T[j]+1)+1.
2010.7.29
SRM 420 DIV1 500 数学期望
有R张红色牌,B张黑色牌,随机抽取,红色得到1分,黑色扣1分,问在最优情况下的分数期望值。
令f[i][j]表示剩下i张红色,j张黑色的数学期望,而且是最优策略下的。
那么f[i][j]=max{0,(f[i-1][j]+1)*i/(i+j)+(f[i][j-1]-1)*j/(i+j)}
f[0][j]=0; f[i][0]=i;
f[r][b]为答案。
2010.8.4
NWERC08 a //ad hoc
给出一个称,而且挂称的地方只在中点,相当于一个二叉树,不会有单个叶子,而且所有叶子都有权值,现在就希望修改最少的叶子节点,使得对于所有非叶子节点,它的左右权值都平衡。
考虑最坏情况下只有一个叶子不会修改,那么所有其他的节点的值都已经被固定下来了,也就是说只要我们枚举固定的那个点,然后看以这个点为标准的话有多少个叶子是不需要修改的,那么取其中的最优就可以了。
对于深度为dep,权值为w的叶子节点,以它为标准,该树的权值总和为w<<dep。对于每个叶子都这样求,看所有其他叶子中和它一样的有多少个就可以了。
NWERC08 c //最小点覆盖(用点覆盖边)
有分别c,d,v个猫,狗和投票者,每个投票者都有自己喜欢和不喜欢的猫狗,现在需要选出一些猫狗,使得满足最多投票者的要求。
把投票者作为二分图的点,然后有冲突的连线,题目就转化为求最小点覆盖问题,使得去掉最少的投票者,使得剩下的投票者之间没有冲突。最小点覆盖问题就是最大匹配问题,由于构图的时候存在对称性,所以令最大匹配为m,那么答案就是v-m/2。
NWERC08 f flood fill
给出一些立方体,然后把些立方体组成的东西放到水里面去,求这个东西和水的接触面积和占水量。
由于坐标很小,所以先进行离散化,然后用100*100*100的数组来表示,接着就对它进行flood fill。逐个进行排查,模拟水和这个东西接触的过程,然后。。。就这样咯。
2010.8.6
SWERC96 f 压缩状态bfs
有r个房间,从1号房间开始,每次只走有灯亮的房间,而且房间之间有灯的控制关系和连接关系,求从1号房间,而且1号房间亮的状态到r号房间,只有r号房间亮的状态至少需要多少步操作,包括开关灯都算一步。
由于r<=10,可以把状态进行压缩,然后就用典型的bfs处理之。
SWERC96 h dynamic programming
给出n个p[i]和d[i],找出m个出来,使得|sigma{p[j]}-sigma{d[j]}|最小,如果相同则取sigma{p[j]+d[j]}最大的那个。并且输出方案。
令f[i][j][k]表示前i个选择j个,而且sigma{p[j]}-sigma{d[j]}=k的最大的sigma{p[j]+d[j]}。
那么f[i][j][k]=max{f[i-1][j-1][k-p[i]+d[i]]+p[i]+d[i],f[i-1][j][k]}
求的时候顺便记录父状态即可。
2010.8.7
NWERC04 a 递推统计
给出n个字符串,合法字符串表示不包含任意一个这些字符串为子串的字符串,把所有的合法串按照字典序排序,给出字符求字典序,给出字典序求字符。
这道题目的一个关键的条件是这n个字符串长度最多为3,所以令f[left][x][y]表示剩余left个字符还没有决定,而且当前以xy为结尾的情况下不包含不合法字符串的有多少种。f[len][0][0]则为长度为len的所有合法字符串个数。
那么left=0时,f[0][x][y]=1;
left>0时,f[left][x][y]=sigma{f[left-1][y][z]},其中xy,yz,xyz都是合法的串(这里就明白为什么要利用的到题目给出的关键条件)。
然后给出序号求字符串的时候,先用f[len][0][0]判断长度,然后再进行逐位判断。给出字符求序号的话利用序号求字符的方法来进行二分就可以了。
具体实现的时候还有许多的细节要注意。
NWERC04 c 最小路径覆盖
给出一些乘客的上车时间地点和终点,问满足所有乘客要求至少需要多少辆出租车。
以每个乘客的乘车要求为点,先拆点i,i',然后如果满足i的情况下能够满足j,那么连边<i,j'>。
然后根据最小路径覆盖和最大二分匹配的关系,在这个图上求最大匹配m,那么答案就是n-m了。算是典型题目。
2010.8.8
NWERC04 h 带模的高斯消元
对矩阵bij=i^(j-1),求a[i],使得在模p情况下得到f[i]。bij,f[i]已知。
就是普通的带模的高斯消元,不过在带模情况下用bii消去bji需要些技巧。由于p是素数,所以对于任何(n,p)=1的n,都有n^(p-1)==1(mod p),所以消去bji的时候,需要找到一个x,使得bji-x*bii==0(mod p),变换得到
bji*bii^-1==x(mod p),而且由费马小定理,左右乘以式子bii^(p-1)==1(mod p),得到:bji*bii^(p-2)==x (mod p)。这就把x找出来了。消成上三角后,最后回代一下就可以了。而且由于p是素数,必定只有一个解。
2010.8.9
SWERC09 a 二分+区间交
给出点集,求出在x轴上离所有点最长的那个最短是多少。
二分长度,然后对于每个点都求在y轴上那个x的范围,求出所有点是否存在交集就可以了。
SWERC09 d 暴力递推求概率
扔飞镖,有20个均匀分布的靶,有2个人玩,开始时大家都有n分,扔到哪块就扣多少分,如果不够扣就保持分数,第一个扣到0分的为胜,A的策略是随便扔,B的策略是瞄准一个扔,但是他所瞄准的及旁边的三个都有相同概率中,他会取其中的最大概率的那个来扔。分别问A先扔和B先扔的赢的概率。
求概率如果不是直接公式的话一般都会用DP做,考虑f[a][b],g[a][b]分别表示当前先手是A和B的情况下,A和B赢的概率,然后dp式子很容易求:
f[a][b]=sigma{1-g[a-i][b]}/20;其中a<i的话g[a-i][b]的值是g[a][b]。
g[a][b]=max{sigma{1-f[a][b-dart[i]]}/3,逐个枚举i,三个一组}。同样如果不够扣就保持分数。
由于式子中包含了未知数,所以一般都会进行暴力处理,100次左右就足够了。
2010.8.10
SWERC 09 j 二分+后缀数组
找出一个字符串中长度最长的出现至少m次的子串。
先求出后缀数组和height数组,然后二分长度,对height分组,如果有一组的个数至少为m,那么该长度有解。
注意m=1的特殊情况。
NWERC07 a 二分+判断
组装一台电脑,需要各种不同组件,每种组件都有不同的生产厂家,其价格和质量不同。一个机器的性能取决于质量最差的那个组件,现在要在有限的预算中组装出质量最好的电脑。
二分那个最差质量,然后对于每种组件找出大于等于这个质量的最便宜的,然后看是否在预算里就可以了。
NWERC07 b 网络流
平面坐标上给出n个石块,有些石块上有青蛙,青蛙最大跳距离为D,而且每个石块最多允许mi只青蛙跳出,问有哪些石块可以成为所有青蛙的集中的地方。
假设石块i原来有ni只青蛙,允许mi次跳出,那么把所有石块拆点,建边<i,i',mi>,和<st,i,ni>,对于距离在D范围内的两点i,j,建边<i',j,mi>,<j',i,mj>。
然后就枚举集中的那个石块,建边<i,ed,inf>,做完后删除这个边。
2010.8.12
NWERC06 i 转化为图论
给出26个字母的排列,问是否是ABC...Z通过两次置换得到的。
我们把这个排列看成是一个置换,不过一次置换相当于原来的两次置换,那么我们先把所有的环都给找出来。然后我们发现对于奇环,一定能构造出原来的置换。而对于偶数环,我们发现它缺少了另外对称的一半,所以如果是合法的话,那么相同长度的偶数环必定有偶数个来配对,否则就无解。
2010.8.13
NWERC06 e 暴力dp
给出n本书的高度h[i]和厚度t[i],放在三层不为空的书架上,问这个书架最小面积是多少。
假定最高的那本书在第一层,那么我们只需要知道后两层的最小高度和以及厚度就可以确定面积了,所以令f[i][t1][t2]表示前i本书,后两层厚度分别为t1,t2下这两层的最小高度和。
有:f[i][t1][t2]=min{f[i-1][t1][t2],
f[i-1][t1-t[i]][t2],
f[i-1][0][t2]+h[i],//t1==t[i]
f[i-1][t1][t2-t[i]],
f[i-1][t1][0]+h[i]}//t2==t[i]
最后枚举f[t1][t2]来判断最小面积即可。
NWERC05 f 暴力枚举
给出n个数,问最小的m,使得所有数mod m的值互不相同。
枚举m,然后直接判断。
2010.8.15
NEERC 09 i 网络流
给出一个有向无环图,求出最少的路径,覆盖所有的边。
这个构图比最小覆盖问题要复杂些,这个是覆盖边的问题,构图如下:
拆点,i,i',统计i的出度和入度之差,d[i]表示出度-入度,如果d[i]>0,那么<i',ed,d[i]>,如果d[i]<0,<st,i,-d[i]>,然后对于邻接矩阵做floyd,如果i可到达j,那么<i,j',inf>。
统计sum为所有d[i]>0的和(d[i]<0的和也可以,因为都是相同的),求图的最大流maxflow,那么答案就是sum-maxflow。这个构图的一个主要思想就是对于那些可以通过合并的度都通过最大流消除,然后剩下的就是必须的。因为每个入度为0的点都必须带出一条路线,但是不一定就能覆盖所有边,所以还需要另外的一些点来带出路线来覆盖。那么对于这些点就不能通过流来消除度,于是就会增加路线数。
NEERC 09 j dp+搜索
n道题目,m种类型,还有这n道题目中做对r题,还有每种类型的正确率(这个正确率的计算有点纠结,0.5会归到最近的偶数上,不是四舍五入也不是五舍六入),求出每种类型的题目数和错误的数,并且使得题目数最多和最少的差距最小。
令f[i][j][k]表示前i种类型,共有j道题目,其中答错了k道是否有可能。记忆化搜索之,顺便建图。最后搜索所有的路径找出差距最小值就可以了。
2010.8.17
NEERC 08 f 递推计算统计
给出一个斐波那契的数字表示法,然后问在二进制的这个表示法中,从1开始的连续N位中有多少位是1。
解题的关键是进行分组统计,按照位数来分,那么第i组有f[i-1]个。
令p[i]=f[i-1]*i,表示每组的位数之和。b[i]=b[i-1]+(b[i-2]+f[i-2])+1表示1。。i-1组的1的个数。
然后通过这些计算这连续的N位得到的最大的整个数n,统计出在二进制的斐波那契表示法中1。。n的1的个数。假设n的表示法中a1,a2,..ak为1,那么答案就是sigma{(i-1)*f[ai]+b[ai]+1}。其中f[ai]的含义需要自己琢磨一下才明白它的原因。最后还需要对n+1处理完剩下的几位。这里要注意f[i]的i可能达到150++。
NEERC 08 h 构造?
给出ai(1<=ai<=i),求出bi,使得sigma{ai*bi}=0。
还没想明白的构造方法,从后往前,s初始为0,若s>0,则加a[i],否则减a[i]。
2010.8.18
NEERC07 a 调整
给出平面上n只蚂蚁和n棵树,求蚂蚁和树的一个对应关系使得这些线段不会相交。
想到了一个调整的方法,先随机分配,然后每次把相交的进行交换,做若干次后就出结果,可能是相交那里有问题,思路和其他的代码和petr一样,petr瞬间出解,但是我的却卡住某个数据,。。。不明白。
NEERC07 l trie+hash
给出若干个单词,构造状态机出来,而且需要最少的状态。
先构造trie,然后对trie进行hash,求不同的值即可。因为对于“最省”的状态机来说,一个状态对应唯一的一个trie子树,然后把每个trie子树变成hash值,看不同的个数就是状态机的状态数了。不过这里还需要注意,对于trie树中非叶子的终止状态,要与同“形状”的trie子树有一些区别就可以了。
2010.8.19
NEERC06 i 数学期望+map
给出无向图G(V, E). 每次操作任意加一条非自环的边(u, v), 每条边的选择是等概率的. 问使得G连通的期望操作次数. (|V| <= 30, |E| <= 1000)
由于结果只和连通的状态有关,所以读入图后求出连通块和他们的个数。设状态s={c1,c2,...,ck},表示由k个模分别为c1,c2...,ck的集合组成的图的状态,为了防止重复,令c1<=c2<=...<=ck。然后考虑连一条边,有2种可能,一个是连回原来的连通块,一个是连去其他连通块。所以令f[s]表示s这个状态的期望,那么有:
f[s]=[c(n,2)-sigma{ci*cj}]/c(n,2) *(f[s]+1) //连到自己原来的连通块,s状态未变
+ sigma{ ci*cj*(f[s'ij]+1)}/c(n,2) //连到其他的连通块,s'ij表示这条边把i,j连通块连在一起后的状态。
把这个式子变换一下,然后就利用记忆化递推,利用map<vector<int>,double> 作为f,很方便的进行状态的表示。写起来很舒服。
NEERC06 c 循环矩阵
给出一圈数a[i],每次对所有位置i,把距离i为d范围内的所有数加起来mod m得到下一轮位置i的值。问k轮之后这圈数的值。
构造一个矩阵A,使得a[i]乘以这个矩阵后得到了一轮过后的值。那么剩下的就容易做了,利用对数复杂度的方法求A^k,最后a*A^k就是结果。不过这里n最大有500,比较慢,不过这里有一个知识点我是不知道的,那么我们分析一下A这个矩阵的特点,A其实是一种循环矩阵,而且A*A得到的结果也是循环矩阵,所以我们就可以只需要求出一行或一列的值,然后循环赋值给剩下的就可以了,于是复杂度变为O(n^2*logk)
2010.8.20
CEERC08 b 扩展欧几里德判断
求a*b的方砖能否铺满c*d的地板。
作以下猜想,该矩形可先分为3种分割方式
1:若干的c*a子矩形
2:若干的c*b子矩形
3:c*x和c*y的子矩形
对于大矩形c*d,我们需要用a边和b边去组合成c边,有3种方案
1:只用a 组合成的子矩形是c*b
2:只用b 组合成的子矩形是c*a
3:既用了a也用了b 组合成的子矩形是c*lcm(a,b)
如果c可以用方案1和方案2:那么d就
(i)只能用b
(ii)只能用a
(iii)既用了a也用了b
如果c只能用方案1:那么d就只能由b组成
如果c只能用方案2:那么d就只能由a组成
如果c只能用方案3:那么d就只能由lcm(a,b)组成
其中求c能否由a,b组成用到扩展欧几里德,看是否有非负整数解。
2010.8.22
ZOJ monthly 3378
给出一个非简单无向图,求出0到n-1的必经边。
先求桥,然后找出0到n-1的随意一条路径,求交集。
ZOJ monthly
2010.8.26
hdu3418 二分+判断
有n种产品,分别有a[i]个,如果收集m种不相同的产品算装备一个人,问最多可以装备多少个人。
二分人数len,然后从a[i]大到填充m*len的方形,如果多出来就放到下一层,只是不要和上一层的同一类型在一起就可以了,用贪心的方法来想就容易理解了。
ural1158 trie图
给出组成单词的字符集,还有一些邪恶单词,问长度为m的所有单词中不包含这些邪恶单词的数量。
先把邪恶单词构成一个trie图,然后就相当于在安全图中从根走m步有多少种走法。这个就可以用地推来做,dp[step,i]表示step步走到i的方法数,然后就直接从根一直递推过去就可以了。
这题要用高精度。
2010.9.2
hdu3468 bfs+二分图最大匹配
给出一个地图,一些地方有金矿,从标志的A走到B再走到C...每次都走最短路,然后可以选择在最短路上某个有金矿的地方挖一次,走一次只能挖一次,然后问最多可以挖多少个。
先求每个标志点到所有其他地方的最短路,然后判断所有金矿,是否在相邻的标志点的最短路上。二分图左边表示相邻路径,右边表示金矿,然后如果金矿在相邻的最短路上则二分图建边,求个最大匹配就可以了。
2010.9.5
pku1637 混合图的欧拉回路
摘自网上的:http://www.cppblog.com/guojingjia2006/archive/2008/08/02/57859.html
原来混合图欧拉回路用的是网络流。
把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。
好了,现在每个点入度和出度之差均为偶数。那么将这个偶数除以2,得x。也就是说,对于每一个点,只要将x条边改变方向(入>出就是变入,出>入就是变出),就能保证出 = 入。如果每个点都是出 = 入,那么很明显,该图就存在欧拉回路。
现在的问题就变成了:我该改变哪些边,可以让每个点出 = 入?构造网络流模型。首先,有向边是不能改变方向的,要之无用,删。一开始不是把无向边定向了吗?定的是什么向,就把网络构建成什么样,边长容量上限1。另新建s和t。对于入 > 出的点u,连接边(u, t)、容量为x,对于出 > 入的点v,连接边(s, v),容量为x(注意对不同的点x不同)。之后,察看是否有满流的分配。有就是能有欧拉回路,没有就是没有。欧拉回路是哪个?察看流值分配,将所有流量非0(上限是1,流值不是0就是1)的边反向,就能得到每点入度 = 出度的欧拉图。
由于是满流,所以每个入 > 出的点,都有x条边进来,将这些进来的边反向,OK,入 = 出了。对于出 > 入的点亦然。那么,没和s、t连接的点怎么办?和s连接的条件是出 > 入,和t连接的条件是入 > 出,那么这个既没和s也没和t连接的点,自然早在开始就已经满足入 = 出了。那么在网络流过程中,这些点属于“中间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反向之后,自然仍保持平衡。
所以,就这样,混合图欧拉回路问题,解了。
/*其实网络流的作用是决定把哪些边反向从而使得度平衡*/
hdu3472 混合图的欧拉路径
这个跟上面的几乎一样,只有一点不同,那就是随意无向边方向后统计度数差为奇数的点数,如果不是2个或者0个,那么无解,然后对于这两个点随意连一条有向边,剩下的和上面一样。
这里的不同在于为什么这两个点也可以随意连边,因为网络流的作用在于决定应该反哪些边使得度平衡,所以如果形成欧拉回路的话,这两点必须要连边,只是方向要由网络流的结果决定。
2010.9.8
hdu3590 树博弈Anti-SG
给出一棵树,两人轮流砍一些树边,谁不能砍则赢,问先手是否有必胜策略。
首先求树的SG值,对于叶子为0,非叶子则是各个儿子的SG值+1的异或和,然后利用sj定理,也就是Anti-SG定理:
SJ 定理:
对于任意的一个 Anti-SG 游戏,如果我们规定当局面中所有单一游戏的 SG 值为 0 时游戏结束,则先手必胜当且仅当以下两个条件满足任意一个:
(1)游戏的 SG 函数不为 0,且游戏中某个单一游戏的 SG 函数大于1。
(2)游戏的 SG 函数为 0,且游戏中没有单一游戏的 SG 函数大于 1。
hdu3584 三维树状数组
给出一个01立方体,有两种操作,把一个子立方变为非,或者问某个小立方块的01情况。
三维树状数组,用加来表示非,通过一个十分对称的加1的方法来模拟异或,这样求1,1,1到x,y,z的和就是x,y,z的01情况。
2010.9.9
hdu3595 Every-SG博弈
每个单一游戏由两堆石子构成,每次选取其中一堆石子,假设有x个,那么可以在另外一堆石子中取k*x个,当然要保证另外一对的石子个数y>=k*x。整个游戏由n个单一游戏构成,然后每次决策都要在所有剩下的还没有结束的单一游戏中进行选择,不能选的为输,问先手是否有必胜策略。
这个原来就是Every-SG博弈,先把所有单一游戏的SG都求出来,然后利用Every-SG定理:
算出每个游戏的SG函数的时候,对于SG不为0的点,最慢几步可以到达终止状态,对于SG为0的点,最快几步可以到达终止状态。
0 v为终止状态
step[v]={ max(setp[u])+1 SG[v]>0 && u为v的后继状态 && SG[u]=0
min(step[u])+1 SG[v]=0 && u为v的后继状态
先手必胜当且仅当单一游戏中最大的step为奇数。
2010.9.10
hdu3562 特殊图的最大环
开始的时候是一个三角形,然后每次新建的点都和某两个原图中就直接相连的点连接起来,问这样的图中的最大环。
开始的时候忽略了那个重要的条件,原图中直接相连的两个点。。。结果就纠结好久。主要的做法就是倒着做,对于i点和它相连的x和y点,如果s[i][x]+s[i][y]>s[x][y]则更新,而且顺便看i,x,y三点是否能形成最大环,最后把开始的三个点也判一下最大环就可以了。
spoj375 树路径剖分
给出一棵树,两种操作,修改某条边的权值,询问两点间的最大边权。
通过轻重边剖分成一条条链,对于每一条链建立一棵线段树,把边权下降到两个端点深度较小的那一个点上,这样就把边权转化为点权。然后修改的时候维护线段树,询问的时候先找出lca,然后从某个点x向上寻找,当x和lca不在同一条链上的时候,x先跳到当前链的顶端,求出这段的最大值,然后再小跳一步到另外一条链上,直到在同一条链上为止。此时,要注意由于我们把边权转化为了点权,对于lca这个点的权值是它和父节点那条边的权值,所以这里询问的时候,是查询lca往下一个节点到x之间的点权。注意好这点就可以了。
2010.9.13
hdu3563 矩形切割
给出若干个n维矩形,求并的空间和(如二维是面积,三维是体积)
矩形切割,用链表实现,先判断是否每一维都相交,然后每次都增加该维上没有相交部分的n维矩形,然后把当前维变成相交的部分,接着去做下一维,最后把切剩的加到链表中去。速度还是很快的。。
对于维数少而矩形多,最好用线段树,维数多而矩形少用矩形切割比较好。
2010.9.15
hdu3589 二次剩余
给出Legendre和Jacobi定义,求所给的Jacobi符号值。
枚举题意,判断是否是二次剩余的时候用欧拉判别法:
p是奇素数,d%p!=0,那么d是模p的二次剩余的充要条件:d^((p-1)/2)==1 (mod p)
zju2314 有上下界的网络流判存在性
构图详见周源的《一种简易的方法求解流量有上下界的网络中网络流问题》,添加源和汇,然后一个最大流就可以了。至于有上下界的网络最大最小流则需要多加一个二分再进行可行性判断。
设f(u, v ) = B(u, v) + g(u, v ) (*),显然0 <= g(u, v ) <= C(u, v) - B(u, v)。将(*)代入流量平衡条件中,则得到∑[B(u, i) + g(u, i)] = ∑[ B(i, v) + g(i, v)] => ∑g(i, v) - ∑g(u, i) = ∑B(u, i) - ∑B(i, v)。如果设M(i) = ∑B(u, i) - ∑B(i, v),即M(i)为流入结点i的下界总和减去流出i的下界总和。
至此,可如此构造一个只有流量上界的附加网络:增加附加源S'和附加汇T',原网络中M(i)非负,则C'(S', i) = M(i),否则C'(i, T') = -M(i);原网络中任意有弧相连的结点u和结点v在附加网络中的弧C'(u, v) = C(u, v) - B(u, v)。
这样,如果附加网络满流,则在原网络中就存在一个与之对应的可行流。而想判断附加网络能否满流可通过求解附加网络的最大流进行判断。如果满流,则有解;否则无解。
这个问题弄明白后,就可以进行下一步的求解有上下界网络中的最大流和最小流问题了。
增加一条弧(T, S),使原网络变成一个无源汇的网络。如果求最大流,则B(T, S) = a,C(T, S) = inf;如果求解最小流,则B(T, S) = 0,C(T, S) = a。可以通过二分法枚举a,按上文提到的方法构造附加网络,判断附加网络中是否有可行流即可。最终,a即为所求。
这种方法实现起来较为简单,所需的代价是多次求解最大流。复杂度为O(logF Maxflow(V, E))。
2010.9.21
hdu3656 二分+最大团
找出至少k个点,使得他们的最近的距离最大。
二分距离,如果u,v的距离大于改距离,则建边,然后看这个图中是否存在>=k的团。
2010.9.28
hdu3627 动态找出某坐标右边最近的点
对输入坐标离散化,然后对x坐标维护一个线段树,每个节点记录当前x区间内最大的y坐标,然后对于l==r的节点,维护一个set<int>,保存当前x坐标下的各个y坐标,插入和删除操作维护这两个东西就可以了。查找的时候,先判断左区间是否有解,无解才去右区间判断。
通过此题,原来set的效率还是灰常高的,在某些处理二维问题上可以给不少力。
2010.9.29
hdu3664 递推
给出n和k,问1~n的排列a1,a2...an,刚好有k个ai>i的排列的个数。
令f[n][k]表示前n个数,有k个ai>i的排列数,那么我们考虑最后一位n,那么n有3种交换的方法,一个是和前面那些ai<=i的位交换,这样k的个数就加1,第二个是和前面ai>i的交换,那么k不变,第三个是摆在原地。于是就有以下递推式:
f[n][k]=f[n-1][k-1]*(n-k) //第一情况
+f[n-1][k]*k //第二情况
+f[n-1][k] //第三情况
2010.9.30
hdu3661 排序
有n份A产品和n份B产品,所需时间分别为xi和yi,共有n个工人去加工,每个工人选择一个A和一个B来加工,如果xi+yj超过常规工作时间T,那么就要付加班费xi+yj-T,问最少要多少加班费。
由于x和y的顺序无关,所以可以先考虑进行排序,按xi-T从小到大排序,然后对yi从大到小排,然后对应的xi和yi一起是最优的,正确性就在于如果进行交换的话不会有更优解,这个需要仔细想想。
hdu3666 差分约束
有一个矩阵cnm,然后问是否存在a1...an,b1...bm,使得第i行所有元素乘以ai,第j行所有元素除以bj后处于[L,U]区间中。
对于cij,那么就是L<=cij*ai/bj<=U,取对数后得到 log L-log cij<=xi-yj<=log U-log cij
然后化成差分不等式:xi<=yj+log U-log cij,yj<=xi+log cij-log L,接着建图,看是否有环。
然后果断的TLE了,后来仔细发现,这个图的特点就是一个二分完全图,所以我猜想每个点进队列的次数肯定是很少的,所以就直接判断看是否>2,然后很无语的过了= -。不解释。
2010.10.1
hdu3667 费用流
给出一个图,每条边有费用系数ai和流量上限ci,然后如果该边流量为x,那么费用为ai*x^2,问从1到n运送k单位流量最少花费。
由于这里的费用计算是x^2,那么一个很神奇的想法就是1+3+5+。。=n^2,也就是拆边,拆成ci个流量为1,费用分别为(2*j-1)*ai的边,那么按照连续最短路增广的方法,肯定是先走1,再走3.。。这样子就能够保证正确性。然后一个最小费用流就可以了。
2010.10.3
pku 3734 生成函数
用四种颜色w,x,y,z染1*n的格子,其中y,z两种颜色需要染偶数个格子,问有多少种方法。
用指数生成函数,得到g(x)=[(e^x+e^-x)/2]^2*e^2x
最后化得:gn=2^(2n-2)+2^(n-1)
2010.10.4
pku3716 条件概率,贝叶斯公式
有4个色子,每局,对于每个色子的每个面,都有平均的几率被刷成红色或黑色,然后再扔色子,现在已知前两局各有p,q个色子抛出红色,问下一次抛出红色的色子个数期望值。
先求出对于单个色子p(x=1 | x=00),p(x=1 | x=01),p(x=1 | x=10),p(x=1 | x=11)的概率,然后找出形成p,q的这4个色子的各种组合情况,那么对于一种组合情况,sigma{p(x=1 | x=??)}为抛出的色子的个数,然后还要乘以1/M,(M为组合总数),那么就变为了求期望值的经典公式形式了。
然后剩下的问题是如何求p(x=1 | x=??) 。考虑到每个色子的不同面数对于求这个概率有联系,那么p(x=1 | x=??)= sigma{ p( T=t | x=??)*p(x=1 | T=t)| 0<=t<=6 }
然后对于p( T=t | x=??)可以利用贝叶斯公式处理:
p( T=t | x=??)= p(x=?? | T=t)*p(T=t) / sigma{p(x=?? | T=t)*p(T=t) | 0<=t<=6}
然后就把p0...p3都求出来了,接着就解决了问题。。。
详细见:http://hi.baidu.com/5l2_/blog/item/dbb67843252e631a73f05df6.html
2010.10.5
hdu3564 线段树+树状数组
给出一个序列的构造方法(从1..n进行添加),然后问每次添加i的时候,序列中的LIS是多少。
先利用线段树反向构造出原来的序列,并且记录每个数在原序列中的位置,然后正向重新构造这个序列,可以利用树状数组动态维护前j个的最大值,由于从1.。n来构造,所以对于第i个而言,它是当前最大的,只要知道它前面的最长就可以了,更新LIS的值。
2010.10.9
zju 3412 容斥原理或mobius函数
给出n个数a1..an,然后对在取值在[x,y]区间内的所有b1...bn,使得s<=sigma{gcd(ai,bi)}<=t的有多少种bi的选择方案。
递推式子很容易求:f[i,j]表示前i个ai与bi,gcd的和为j的情况下的方案数。那么有:
f[i][j]=sigma{f[i-1][j-di]*S[A;ai/di]},其中di是ai的约数,A表示区间[x/di,y/di],S[A;k]则表示在A数集里面,和k互质的数的个数。那么现在问题就在于如何求S[A;k]
通过mobius函数,能够求出一个数和一个数集的互质的个数,有下面的定理:
S[A;k]=sigma{u[d]*|Ad|},d是K的约数,Ad表示A数集中能被d整除的数的个数。
mobius函数可以利用线性筛素数的方式预先处理出来,S[A;ai/di]则可以在进入j的循环前处理出来,于是总的复杂度为O(n*(Range(ai)+t*sqrt(Range(ai)))
zju3329 数学期望(把环化成一次方程)
有三个色子,分别有k1,k2,k3个面,每次同时抛出这三个色子,如果第1,2,3个分别为a,b,c,那么积分归零,如果超过n积分则结束,问游戏结束的期望步数。
以下是官方解答:dp[i]用来表示当前总和为i时,到游戏结
束的期望步数。则当i>n时,dp[i]=0,否则dp[i]=sigma(p[k]*dp[i+k])+pp*dp[0]+1
其中p[k]为扔到总和为k的概率,pp为扔到abc的概率。这个时候按照左电梯的思路,
是要写成矩阵然后高斯消元,不过这题的n有500这么大,又有300个case,N^3的高斯
消元显然是吃不消的。观察后发现,每个dp[i]除了跟dp[0]有关,就只和比i大的dp
值有关了。于是,我们可以让i从n到0,一路都把dp[i]表示成dp[0]的一次函数,最后
就是一个dp[0]=a*dp[0]+b的式子了,直接解出dp[0]即可,复杂度非常小。
2010.10.16
zju3404
摘引自watashi的报告:“那个,首先背景和配图什么的就略过了。题目说的就是你有m种交换方式,用a交换别人的b,这可以看成一个a到b的有向边,题目保证了每个顶点的入度和出度都不超过1。题目问的是有多少种不同的序列,能够通过变换,最后成为一个n的排列。
注意每个顶点的入度和出度都不超过1,所以每个联通分量只有可能是链或环。对于环的情况,显然就可以任意分配了,所以环内部任意交换的顺序有mm(A000312)种。对于链的情况,这是一个非常经典的问题,答案是m+1m-1(A000272)种(一个非常漂亮证明),也可以通过动态规划dp[i][j] = sum{c[j][k] * dp[i - 1][k]}求得,其中答案就是dp[m][m],c[j][k]表示j选k。有了这些基础,就只要先构图,再求出所有联通块的大小,并判断它是链还是环,最后直接算出答案。”
这里需要注意的是:dp[i][j]表示j个位置放1..i的方案数,首先要知道对于链表状态的,我们可以先把它们规约为1..i放在j个位置上的情况,然后如果要变为合法的排列的话,要符合j<=i,这也是理解这个递推式子的关键,如果不符合这个条件则无法通过单向链表形成合法的排列,而对于当前的i的每一种选法都有c[j][k]个状态,所以就有这个式子。
hdu3663 D-link精确覆盖
给出一些城镇,每个镇都有发电站,这些发电站都有一个发电的时间区间,而且每个发电站只能在这个时间区间的一个子集时间上发电,而且停了之后就不能再工作,某个镇发电的时候,相邻的镇就有电,但不能同时发电。现在要求每个镇在1.。D天都有电供应,问每个镇的供电时间表。
把这个问题转化为精确覆盖问题,也就是在n*m的01矩阵中选出一些行使得对于每一列都有且只有一个1。转化的方法就是化成(n*16)X(n*d+n)的矩阵,这里的16是指[1..5]的所有子区间和[0,0],表示了每个镇的每一个发电时间区间,也就是所选出的行,对于列,则表示每个镇的1.。d天都要有唯一来源的供电,最后的n列是表示,一个镇的发电区间只能选一个,这样就对应了题目的要求。
这样转化之后就是经典的Dlink,直接模板之。
pku3074 数独dling做法
把数独转化为精确覆盖,变为(9*81)X(9*9+9*9+9*9+81)的矩阵,关于列的说明,首先是1~9行,每行有1..9的选择,每行都要有唯一的1..9,然后对于每一列和每个宫格都是如此,所以就有前面3个9*9,最后一个81表示对于每个格子,也是选且只选一个值。对于行来说就是提供选择给各个列,那么对于每个空格,有9种填法,对应有9行,空格最多有81个,而对于已经填好的,那么就只有1行。
pku3076 和上题一样,不过是16*16的。
2010.10.17
hdu3617 递推
给出N个学生,以及他们对自己成绩的猜测ri和bi,表示他的成绩顺数ri和倒数bi,问最多有多少学生能猜中。
其实对应于n区间[ri,n-bi+1]中的成绩是一样的,然后问能组成完整的1..n的区间组合中区间数量最多的是哪个。注意同一个区间的猜测人数可能会大于该区间大小的情况,此时要排掉多余的,然后就是简单的dp了。
2010.10.18
hdu3533 字符串,后缀数组
给出一个字符串和k,问这个字符串的所有子串中字典序排第k的是哪个。
大致做法,先求出后缀数组,现在考虑答案的第一个字符,先找出最前的,而且所有子串个数总和>=k的这个位置,然后这个位置的第一个字符就是答案的第一个字符了,然后找出后缀数组中第一个字符是这个字符的范围,k要减去这个范围之前的那些子串个数,然后让当前的区间变为我们所找到的范围,下一次就在这个范围里继续做。对于第二个字符也是同样的做法。
实现的时候有很多细节,文字很难表达。。。
2010.11.6
hdu3686 双连通分量,缩点
问某边到某边必须经过的点数,先求各个割点,然后求出双联通分量,每条边都属于一个双联通分量,然后对于每个联通分量和割点组成新的图,显然这个图是一棵树,然后对于每个询问就在这棵树上做Lca,然后就可以求出某边到另外一条边所必须经过的点数。实际写起来需要注意好多东西。。。
2010.11.11
pku 1015 dp
在遥远的国家佛罗布尼亚,嫌犯是否有罪,须由陪审团决定。陪审团是由法官从公众中挑选的。先随机挑选n个人作为陪审团的候选人,然后再从这n个人中选m人组成陪审团。选m人的办法是:控方和辩方会根据对候选人的喜欢程度,给所有候选人打分,分值从0到20。为了公平起见,法官选出陪审团的原则是:选出的m个人,必须满足辩方总分和控方总分的差的绝对值最小。如果有多种选择方案的辩方总分和控方总分的之差的绝对值相同,那么选辩控双方总分之和最大的方案即可。
动态规划状态表示: VALU_MAX 表示最大喜好分值。 p [k] , d[k]分别表示第k个人对原被告的喜好分值。
Last[i][j] 表示已经选了i个人得到差值j(j = D(J) - P(J)+ VALUE_MAX * m)的时候,和i个被选中的人的编号k(k = 1到n) Sum[i][j] 表示已经选了i个人得到差值j(j = D(J) - P(J)+ VALUE_MAX * m)的状态时最大的(D(J) + P(J))值。
状态转移方程: Sum[i + 1][j + p [k] – d[k]] = max(sum[i + 1][j + p[k] – d[k], sum[i][j] + p[k] + d[k]) (其中第k个人和须在前i次选择中没被选中) 最终选出方案 K = min{ i | 0 <= i <= value_max * m && (sum[m][value_max * m + i] || sum[m][value_max * m – i]) >= 0 }再利用last数组查出记录。
这里循环的时候,顺序为m,j(差值),n,这样循环n的时候,要进行重复判断,如果先进行n再进行m的循环,那么会造成重复,而且不容易进行重复判断。
2010.11.12
pku3683 2-sat+方案输出
给出N个婚礼,每个婚礼有开始和结束时间Si,Ti,还有婚礼中的宣言的时间长度Di,而宣言的时间要么是在婚礼一开始或者在婚礼最后的那段时间进行,然后要参加所有的婚礼,问一个方案。
对于2-sat问题,主要走两个步骤,第一个是分组,每组2个,而且是两者不能都选,只能选一个。不同的题目对于分组的概念不同,例如这道题目是明显的给出分组的,每组都必须要选且只选一个,而有的题目只说明要取一些,每个东西都可选可不选,而通过拆点,拆成x和~x,那么就变成了每组都必须要选一个的情况。第二个就是建立组和组之间的矛盾,这个就通过析取式完成,于是就完成构图了。
对于输出方案的方法,先对scc缩点,对于x和~x,要找出缩点后对方所在的缩点的编号,然后拓扑排序。接着以相反的拓扑顺序,对于没选的点,选择之,对于不选的那些,就要把所有指向它的点都不选(这里就需要知道x和~x对方所在的缩点编号)。最后输出即可。
2010.11.13
pku2699 网络流
给出一个有向图的出度序列,然后如果某个点有边指向所有出度比它大的点,那么这个点就称为king。现在问所给出的出度序列所构成的图中,最多能有多少个king。
这里有个很巧妙的构图方法:
“设一个源点S引一条边到每个人,边容量为这个人打赢别人的数量 ,
N个人两两比赛共N*(N-1)/2场比赛,每场比赛只有一个胜出,所以每场比赛引一条边到汇点,容量为一,表示最后赢的总场数为N*(N-1)/2而这些由这N个人去瓜分,
每场比赛有两个人参加,所以,这两个人各自引一条边到这场比赛,如果A在某场比赛打羸了B,那说明这场比赛只能让A到达T,从而使A赢的场数增加1,这时只要把B引向这场比赛的边去掉便可!
由于要使得King更多,而最有可能成为King的人中分数高的比分数小的人的概率要大,所以从高分往低分枚举,由于枚举到第i个人时要打败前面i-1个人才能成为King ,所以,把凡是有i和前面i-1个人参加的比赛都定为i赢,即去掉i-1个与相关比赛的边,做一次最大流,如果等于SUM(所有人赢的场数)则枚举下一个人,否则结束!”
2010.11.18
zju3421 三分
给出n个函数fi(x)=ax^2+bx+c,定义F(x)=max{fi(x)} ,0<=x<=1000。求min{F(x)}
通过观察,发现F(x)函数是一个单峰函数,于是就可以直接用三分法求峰值,注意精度要至少2倍于输出精度,我选了1e-10。
///////////////////////new age///////////////////////////////////////////
2011.1.19
swerc10 d 网络流+扩展路判断
给出一个矩阵,矩阵元素要么是0或者1,并且给出每行和每列1的个数,然后问是否有解,如果有解,给出字典序最小的那个。
求是否有解可以直接利用网络流得到。如果满流则有解,现在是考虑如何使得字典序最小。那么我们可以按照先行后列的形式,如果某个位置为1,那么考虑把这个1退流,然后判断在只改变优先顺序比这个后的点的情况下(优先顺序高的不能变),是否存在扩展路,如果存在,那么就是说当前元素就可以变成0而继续有解,这样字典序变小而不改变解性质。
2011.1.20
uva 11874 转化成判正环
给出一个带权有向图,每条边有收入和支出,问能否找到一条点不重复的环,使得总收入/总支出>=p,其中p给出。
sigma{income} /sigma{outcome} >=p 转化为 sigma{income}- p* sigma{outcome} >=0 也就是对于每条边权值化为 in-p*out 然后看是否存在正环即可。这个用bellmanford就可以解决。
2011.1.23
seerc10 d 格雷码,网络流
有n个竞赛和m个题目,每个竞赛都有固定的题数,每道题目有一些适合的竞赛,如何分配问题使得可以同时举办最多竞赛,每个问题只能分配到一个竞赛。
由于竞赛数<=15,可以枚举哪些竞赛必须得到满足,然后构图,如果满流则有解。这里有个优化就是通过格雷码来枚举,每次都只需要修改一个竞赛的状态,这样子再进行增广的时候就可以少很多重复工作。然后还有一些简单的优化就可以很快了。
2011.2.15
zju Jan monthly A:
给出n,(0<=n<=99),求出最小的m,使得1/m产生的小数,除去前导0,剩下的连续的2个组成的数能够包含0~99中除n以外的数.
对于1/m,做m次之后就有循环节,所以最好的方法是做m次,暴力打表即可.
当然也可以判断循环节,不过前导0不加入set中,否则会使得把00的情况乎略掉.
小技巧:
求出一个状态s的所有子状态,可以这样写:
for(int i=s;i!=0;i=(i-1)&s)
i ... //这里的i就遍历了所有s的子状态,而且不会有无效状态,关键是 (i-1)&s ,是比i小的最大的那个子状态
2011.2.16
hdu 3762(2010 Northeastern European Regional Contest k)
给出一个无向图,有奇数个点,求出一个k染色方案(k为奇数,且不小于最大的点的度数).
由于有奇数个点,而且图的度数之和为偶数,那么必然存在一个度数为偶数的点,然后由于k为奇数,所以以某个度数为偶数的点开始dfs,考虑这棵dfs树,根最多有 k-1个儿子,那么必然能将所有儿子染色,然后再递归到每个子树,每个子树的根都已经被染色,如果这个根是偶度点,那么必然能继续染色,如果是奇点,那么由于有父亲节点,剩下最多k-1个儿子,所以也必然能继续染色.
于是,这个图必然有解,任意点开始染色即可.
2011.2.22
hdu 3735 矩阵乘法
Given two integers N and M, we define a recursive sequence g[i] (indexed from 0) as follows:
(1) If 0 <= i < M, then g[i] = a[i]
(2) If i >= M, then g[i] = b[0]*g[i-M] + b[1]*g[i-M+1] + ... + b[M-1]*g[i-1]
Now your task is very simple: Try to find g[N] mod 1,000,000,003.
传统的做法显然是不能过的,不过矩阵中有一个定理:A^m=sigma{b[i]*A^i | 0<=i<m }.有了这个定理之后使得对于求A^n变为求A^n的一个线性表达(其实就是转换了一种表达方式,而且要计算这种表达方式会少些计算).于先求出C[i][j]:表示A^i 中A^j项的系数. 0<=i<2*m-1. c[i+1]可以由c[i-1]乘以A,然后将A^m的线性表达式又代入原来的线性表达式,就可以求出当前c[i+1]的线性表达式了.
把C[i][j]求出来之后,只需要求A^n-m+1的线性表达式就可以了,这个可以log时间完成.只是两个线性表达式相乘得到的线性表达式需要对一些指数>=m的进行处理,降为<m的.最后把A^m-1...A^0化掉(和a相乘),再和B(A^n-m+1的线性表达式)相乘得到答案.
详细解题报告:http://wenku.baidu.com/view/e7513a2f453610661ed9f470.html
2011.2.23
hdu 3736
把m个人放入n个矩阵中,其中矩阵i长宽为ni*mi,每行每列不能放超过2个人,问有多少种方法.
f[i,j]为前i个矩阵放j个人的方案数,那么f[i,j]=sigma{f[i-1,j-k]*g[i,k]} ,g[i,k]为第i个矩阵放k个人的方案数,那么如何求g[i,k]呢?
令c[i][t0][t1][t2]表示前i行,其中有t0列为0人,t1列为1人,t2列2人.那么考虑当前行不放人,放1个人,放2个人的5种情况递推就可以了.注意优化.
2011.3.2
zju 3475 枚举+最小割
在一个20*20的方格中,建造一些围墙,使得X和某些A与E和外界都不联通,建造围墙有对应的花费,而对于满足条件的A,有对应的收入。
首先2^5枚举哪些A要被围住,然后就要求所需的最小费用,这就是典型的最大流最小割问题。其中X和所枚举的A同源连一条流量为inf的边,E和边界同汇连一条流量为inf的边。
zju 3474 贪心
某人要挑战n个人,有三种攻击分别消耗p1,p2,p3能量,分别获得3,2,1分,每次都至少拿7分才过关,血要多于0,开始有s血,问结束时最多剩多少血.
首先,对于打倒某个对手至少需要多少体力,我们可以通过DP求得,实际上考虑背包大小只有7,只有三种物品,所以直接暴力三个for循环更简单。然后这个问题就和ZOJ3077 Move to Baggage Office类似了。所以可以直接参考这题的解题报告和证明。详见《ZOJ月赛的三个tooold解题报告》。根据证明可以知道,对于恢复的体力小于消耗的体力的战斗,应该按照恢复体力降序排列的顺序打。而对于恢复体力大于消耗体力,我们要用另一种贪心方式:按消耗体力升序排列的顺序打,这个证明非常显然,就不详细说明了。当然,总的顺序是先打恢复体力大于消耗体力的。所以是O(nlgn)的贪心。
ural 1817 数学期望
有一个环型木马,每秒转一格,每次每个小孩都随机站在某个位置上,若有空位则上去,没有则等待直到有位.问第i个小孩等待时间的数学期望值是多少.
令f(s)表示木马的状态为s的概率,f(s)=sigma{f[s']*1/n} s'是去掉某个1的s的子集.然后g[k]表示二进制有k个1(也就是有k个小孩)的等待数学期望值,那么g[k]=sigma(f[s]*1/n*step[s,i]) step[s,i]是在s状态下,在i位置的等待时间.k为站在i位置的人坐上去之后的状态的二进制的1的个数.
打表才能过.
2011.03.5
codeforce round 58 D
给出一个图的欧拉回路的点序列,然后求出这个图的欧拉回路中字典序刚好比给出的大的那个序列.
其实求字典序小的欧拉回路的求法直接在扩展的时候按照点从小到大扩展就可以了.只是这题需要记录第一次走的时候所选的点,然后在回溯回来的时候所选的点比原来的大就可以了.其实本质就是搜索,但是由于欧拉回路都很容易找出来,所以速度还是很快的.
Network Flows p259 Application 8.2
给出一个无向图,对于每条边i,j都有刷新次数aij,每一天都能对所有点j的相邻边进行共bj次的刷新(每条相邻边可能分到的刷新次数不一样).问最少需要多少天使得每条边都满足了刷新次数.
建立二分图,左边是n个点,右边是n(n-1)/2个点,代表边i-j,建立边<s,i,r*bi>,<i,i-j,inf>,<j,i-j,inf>,
<i-j,t,aij>.然后二分r,看是否满足所有aij.
Network flows p720 最大闭合权图
给出一个有向图,点有权值,闭合图是G=(N,A),使得 for each node i in G'; for i,j in A 都有 j in G'.
也就是说有i在里面,i所指向的所有点也在G里面.
求出最大权值的闭合图.
对于wi>0的,建立边<s,i,wi>,对于wi<0,建立边<i,t,-wi>,对原图边i,j建边<i,j,inf>.这样求最小割,用权值和减去最小割就是最大权闭合图.(因为每个割都对应一个闭合图,详细见书的证明)
Network flows p721 application 19.1 open pit mining
有一堆砖头,每个砖头都有价值wi(可正可负),要挖下面的砖头必须先把架在这个砖头上的砖头都挖走才可以,问获得的最大价值是多少?
建图时,下面的砖头向上面的砖头连inf的边,表示一种拓扑关系.
典型的闭合权图....
Network flows p721 19.2 Selecting Freight handling terminals
给出无向图,边有权,点有负权,要获得边的权,必须要安装边所连的点的终端,问获得的最大权是多少.
把边化成点,左边是n*(n-1)/2个点,右边是点,每条边连两个点,然后就是最大闭合图.(由于选边必须选点,所以边连inf的边到点,也表示一种拓扑关系).
Network flows p727 19.5 Asymmetric Data Scaling
有n行m列的矩阵aij,是否存在Ai(1<=i<=n),和Bj(1<=j<=m),使得对aij,有L<=aij*Ai/Bj<=U.
不等式取对数,化为和式,然后移位,就化为了差分约束系统.
2011.3.9
uva 11090 最小平均值环
一張圖上每條邊都有權重,最小平均值環是「權重除以邊數」最小的環,可能有許多只。
最小平均值環也可以視作是最小比率環的特例,當每條邊的第二組權重都等於 1 的時候。
令V為圖上的所有點構成的集合,n為圖上的點數。
圖上任意取一個點作為起點,d(k, i)為起點走k條邊到達i的最短路徑。
d(n, i) - d(k, i)
平均權重 = min max ─────────────────
i∊V 0≤k≤n-1 n - k
如果圖上有不連通的部分,可以使用最短路徑 Johnson's Algorithm 所提到的技巧,在圖上另外新增一個起點,並且增加起點連到圖上其他點的邊,其權重皆設為零。如此一來,圖上的每一個點都可以由起點走到,而且最小平均值環也不會改變。
2011.3.10
Network flows p734 Just-in-Time Scheduling
有n个工作,不同工作之间有先后关系,每个工作有耗时ci,并且对于工作对<i,j> j必须要在i开始之后aij时间内完成(aij<=ci) ,问完成所有工作的最短时间是多少.
设u[i]表示i开始的最快时间,那么对于<i,j>有: u[i]+ci<=u[j]<=u[i]+aij 移位一下,然后就是差分约束鸟!
Network flows p302 最大区间权值和
给出n个区间,每个区间有范围[xi,yi],然后最多能够同时存在k个区间,每个区间有价值ci,和数量bi,问在满足要求的情况下最大的权值和.
这是个最小费用流问题.建立源汇s,t,然后对于s,1,2...n,t相邻间连边<i,i+1,k,0> 费用是0.对于区间<xi,yi>建立边<xi,yi,bi,-ci>.然后求最小费用流就可以了,每个费用流的答案都对应了一种方案.
Network flows p303 Scheduling with Deferrral Costs
给出p个工作,和q个机器,工作i如果在机器上第k个运行,那么耗时为c[i][k].问把所有工作完成最少耗时是多少.
化成最小费用流来做.左边是p个点,s连到每个点<s,i,1,0>. 右边有p/q上取整个点,假设为r个点.那么对于右边的点j ,建边<j,t,q,0> 表示这个点最多容纳q个作业同时运作(其实就是q个机器同时开工).然后对于左边的每个点i都向右边每个点j建立一条边<i,j,1,c[i][j]>.然后求最小费用流就可以了.(至于右边为p/q个点的原因是,这是个完全二分图,p/q上取整个点肯定能容纳p个工作流,必然有解.)
Network flows p743 有向图和无向图的中国邮路问题
中国邮路问题,其实就是在一个有权图中,从某个点开始,每条边至少走一次,最后又走到起点,求最小花费.
其实中国邮路问题和欧拉回路有很大的联系.
对于有向图而言,可以用最小费用流解决.设每个点的入度为ri,出度为ui,对于ri>ui,连边<s,i,ri-ui,0> ,对于ri<ui,连边
<i,t,ui-ri,0>,对于原图边则容量无限,费用不变.然后就可以通过最小费用流解决.
对于无向图而言,把所有的奇度点找出来(而且必定有偶数个,想想为什么?),然后变为完全二部图,相互连接,权值为两点间的最短路.求一个最小权匹配就可以了.
Network flows p749 动态运输(最短路或最小费用流)
有一个商店要进行n天的销售,每天都有一定的销售需求di,每天可以选择从批发市场进货,但是每个货物需要ci的价格,当然也可以用以前卖剩下的来继续卖,但是每件货物存一天就要wi的花费,问完成这n天的销售最少花多少钱.
先考虑建图,弄源s和s',<s,s',sigma{di},0> ,然后对于<s',i,inf,ci>,对于这n天相邻的两天<i,i+1,inf,wi>.最后对于每一天<i,t,di,0>.
如果每天的供货都是无限的而且仓库也是无限大的话,那么可以直接用最短路来求.
否则供货有限,仓库也有限,那么就可以用最小费用流来求.
NCPC 2010 G DP
给出n,求n的所有排列形成的置换中,环的长度不超过k的概率。
令p[n]表示n个数还没形成环,而且符合k的要求的概率,那么p[n]=1/n* sigma{p[n-i] | 1<=i<=k}。考虑当前剩下的n个数,从某个数开始,一直找到环为止,而且剩下的每个的选择都是等概率为1/n的,所以就有这个结果。加个优化就可以O(n)了。
NCPC 2010 E 分析
给出n×m的方格,然后从1,1开始向右下角走,遇到边界反射,问最终有多少格被走过。
首先考虑把x和y的运动独立,然后最后结束必定是在四个角落上,所以x走到边缘的步数总是(n-1)*k,而对于y也是(m-1)*k',那么当x和y都走到边上时,也就走到了角落上,于是总的步数就是LCM(n-1,m-1),然后加上开始的那个空格,加1.
这时候,就要考虑重复点的问题,对x而言,跨越上下一共走了L/(n-1)次,而跨越左右则有L/(m-1)次,那么相互之间就共有L/(n-1) * L/(m-1) 次相交。但是还有一些是相连而不是交叉,那么这些点都是“碰壁”的点,而且要么是x碰壁,要么是y碰壁,所以总数为L/(n-1)+L/(m-1)-1 ,-1是因为最后一步是同时碰壁。然后就是由于x和y的相交是双向的,多算了一倍,要乘以1/2.
于是总数为L+1-1/2*(L/(n-1)*L/(m-1)-(L/(n-1)+L/(m-1)-1))=L+1 - 1/2*(L/(n-1)-1)*(L/(m-1)-1)。
NCPC 2010 J 离散化
给出平面上若干的梯形,其中有三面都垂直xy轴,且都平放在x轴上。现在按照从近到远的顺序给出这些梯形。然后问对于每个梯形,能看到的面积是多少。
离散化+判断。先对x坐标都进行离散化,然后再加入那些斜线相交的点来一起离散化,接着根据这些来切梯形的斜边,把梯形都切为一个个斜线段,然后按顺序计算每个小的三角形或四边形是否在某个梯形内,然后把面积加进去就可以了。
NCPC 2010 B 2次BFS
给出n*m方格中的A,B ,C ,D点,然后A曼哈顿连线到B点,C连到D点,线不可相交,问最短路线是多少。
一个很重要的思路就是,两条线路必定有一条走的是最短路,否则肯定不会是最优。因此就分别让AB先走最短路,或者先让CD走最短路,然后最小值即可。