-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
1227 lines (1227 loc) · 952 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><![CDATA[Atcode1]]></title>
<url>%2F2020%2F03%2F03%2Fatcode%2F</url>
<content type="text"><![CDATA[C++一点内容:久违了,ACM这次就再来刷一次吧链接BingoTime Limit: 2 sec / Memory Limit: 1024 MBScore :200pointsProblem StatementWe have a bingo card with a 3×3grid. The square at the i-th row from the top and the j-th column from the left contains the number Ai,j.The MC will choose N numbers, b1,b2,⋯,bN. If our bingo sheet contains some of those numbers, we will mark them on our sheet.Determine whether we will have a bingo when the N numbers are chosen, that is, the sheet will contain three marked numbers in a row, column, or diagonal.ConstraintsAll values in input are integers.1≤Ai,j≤100,Ai1,j1≠Ai2,j2((i1,j1)≠(i2,j2))1≤N≤101≤bi≤100bi≠bj(i≠j)InputInput is given from Standard Input in the following format:12345A11,A12,A13,A21,A22,A23,A31,A32,A33Nb1⋮bNOutputwe will have a bingo, print Yes; otherwise, print No.```12`Sample Input 1 `84 97 6679 89 1161 59 778978779248430123`Sample Output 1 ````YesWe will mark A11,A21,A22,A33, and complete the diagonal from the top-left to the bottom-right.Sample Input 212345678941 7 4626 89 278 92 85645165717Sample Output 2123We will mark nothing.`Sample Input 3 `60 88 3492 41 4365 73 48106043881148736541923412`Sample Output 3 ````YesWe will mark all the squares.题意:3*3的矩阵,先输入数字填满矩阵,然后输入N个数字,如果方阵里面有这些数字,就标记一下如果标记的数字在一行或一列或对角线上面有3个的话,就输出Yes,否则输出No注意看题!!!仔细看题!!!题解:写的有点麻烦了,,,1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253#include<bits/stdc++.h>using namespace std;const int maxx = 4;int a[maxx][maxx];int b[101];int c, d, e, f, g, h, k, m;map<int, int> mp;int main(){ int N, x; for(int i = 0; i < 3; i ++) { for(int j = 0; j < 3; j ++) { cin >> a[i][j]; b[a[i][j]] = false; mp[a[i][j]] ++; } } cin >> N; for(int i = 0; i < N; i ++) { cin >> x; mp[x] ++; if(mp[x] == 2) b[x] = true; else b[x] = false; } for(int i = 0; i < 3; i ++) { for(int j = 0; j < 3; j ++) { if(i == 0 && b[a[i][j]]) c ++; if(i == 1 && b[a[i][j]]) d ++; if(i == 2 && b[a[i][j]]) e ++; if(j == 0 && b[a[i][j]]) f ++; if(j == 1 && b[a[i][j]]) g ++; if(j == 2 && b[a[i][j]]) h ++; if(j == i && b[a[i][j]]) k ++; if(((i == 0 && j == 2) || (i == 1 && j == 1) || (i == 2 && j == 0)) && b[a[i][j]]) m ++; } } if(c == 3 || d == 3 || e == 3 || f == 3 || g == 3 || h == 3 || k == 3 || m == 3) cout << "Yes" << '\n'; else cout << "No" << '\n'; return 0;}]]></content>
<categories>
<category>C++</category>
</categories>
<tags>
<tag>C++</tag>
<tag>ACM</tag>
</tags>
</entry>
<entry>
<title><![CDATA[CTF习题]]></title>
<url>%2F2019%2F11%2F29%2FCTF%2F</url>
<content type="text"><![CDATA[Web习题CTF入门传送门:习题集]]></content>
<categories>
<category>CTF</category>
</categories>
<tags>
<tag>CTF</tag>
<tag>南邮CTF</tag>
<tag>BugKu</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Rday22]]></title>
<url>%2F2019%2F11%2F05%2FRday22%2F</url>
<content type="text"><![CDATA[Rday22最小生成树 + CTF入门P1111 修复公路题目背景AA地区在地震过后,连接所有村庄的公路都造成了损坏而无法通车。政府派人修复这些公路。题目描述给出A地区的村庄数NN,和公路数MM,公路是双向的。并告诉你每条公路的连着哪两个村庄,并告诉你什么时候能修完这条公路。问最早什么时候任意两个村庄能够通车,即最早什么时候任意两条村庄都存在至少一条修复完成的道路(可以由多条公路连成一条道路)输入格式第11行两个正整数N,MN,M下面MM行,每行33个正整数x, y, tx,y,t,告诉你这条公路连着x,yx,y两个村庄,在时间t时能修复完成这条公路。输出格式如果全部公路修复完毕仍然存在两个村庄无法通车,则输出-1−1,否则输出最早什么时候任意两个村庄能够通车。input123454 41 2 61 3 41 4 54 2 3output15Note12N<=1000,M<=100000x<=N,y<=N,t<=100000code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859#include<bits/stdc++.h>#define INF 0x3f3f3f3f#define eps 1e-8#define pr pair<int,int>using namespace std;typedef long long ll;const int maxx = 5005;struct node{ ll x, y;}No[maxx];bool vis[maxx];double d[maxx];int n;double dis(int i,int j){ return sqrt((No[i].x - No[j].x) * (No[i].x - No[j].x) + (No[i].y - No[j].y) * (No[i].y - No[j].y));}void prim(){ for(int i = 1; i <= n; i ++) d[i] = 1e9; d[1] = 0.0; double ans = 0.0; int id; double minn; while(1) { id = -1, minn = 1e9; for(int i = 1; i <= n; i ++) if(!vis[i] && d[i] < minn) id = i, minn = d[i]; if(id == -1) break; vis[id] = 1; ans += minn; for(int i = 1; i <= n; i ++) { double tmp = dis(id, i); if(!vis[i] && d[i] > tmp) d[i] = tmp; } } printf("%.2f\n", ans);}int main(){ scanf("%d", &n); for(int i = 1; i <= n; i ++) scanf("%lld %lld",&No[i].x, &No[i].y); prim(); return 0;}]]></content>
<categories>
<category>ACM</category>
<category>CTF</category>
</categories>
<tags>
<tag>CTF</tag>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>review</tag>
<tag>最小生成树</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Rday21]]></title>
<url>%2F2019%2F10%2F23%2FRday21%2F</url>
<content type="text"><![CDATA[Rday2并查集 + 贪心 + CTF入门Cyclic Components1234567891011121314151617181920212223242526272829You are given an undirected graph consisting of nn vertices and mm edges. Your task is to find the number of connected components which are cycles.Here are some definitions of graph theory.An undirected graph consists of two sets: set of nodes (called vertices) and set of edges. Each edge connects a pair of vertices. All edges are bidirectional (i.e. if a vertex aa is connected with a vertex bb, a vertex bb is also connected with a vertex aa). An edge can't connect vertex with itself, there is at most one edge between a pair of vertices.Two vertices uu and vv belong to the same connected component if and only if there is at least one path along edges connecting uu and vv.A connected component is a cycle if and only if its vertices can be reordered in such a way that:the first vertex is connected with the second vertex by an edge,the second vertex is connected with the third vertex by an edge,...the last vertex is connected with the first vertex by an edge,all the described edges of a cycle are distinct.A cycle doesn't contain any other edges except described above. By definition any cycle contains three or more vertices.There are 66 connected components, 22 of them are cycles: [7,10,16][7,10,16] and [5,11,9,15][5,11,9,15].`Input:`The first line contains two integer numbers nn and mm (1≤n≤2⋅1051≤n≤2⋅105, 0≤m≤2⋅1050≤m≤2⋅105) — number of vertices and edges.The following mm lines contains edges: edge ii is given as a pair of vertices vivi, uiui (1≤vi,ui≤n1≤vi,ui≤n, ui≠viui≠vi). There is no multiple edges in the given graph, i.e. for each pair (vi,uivi,ui) there no other pairs (vi,uivi,ui) and (ui,viui,vi) in the list of edges. `Output:`Print one integer — the number of connected components which are also cycles.123456789101112131415161718192021222324252627282930313233343536373839404142Example:Input5 41 23 45 43 5Output1 Input17 151 81 125 1111 99 1515 54 133 134 310 167 1016 714 314 417 6Output2 Note:In the first example only component [3,4,5][3,4,5] is also a cycle.The illustration above corresponds to the second example.题意:1.通过观察发现单圈环里的顶点的度都为2,所以并查集找连通图,sum存顶点度数,遍历查找单圈环。2.并查集判环大致就是在两个点进行unite操作时先判断一下父节点是否相同,不相同的话就正常把两个点放进一个集合,如果相同,说明这两个点已经处于一个集合中了,再把这两个点联通,也就出现了环。code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566#include<iostream>#include<stdio.h>#include<cstring>#include<algorithm>#include<cmath>#include<queue>#include<stack>#include<vector>#include<map>using namespace std;typedef long long ll;const int mod = 1e9 + 7;const int INF = 0x3f3f3f3f;const int maxx = 2e5 + 7;int n, m, ans;int par[maxx] , sum[maxx];struct edge{ int u, v;};void init(int n){ for(int i = 0; i < n; i ++) par[i] = i;}int find(int x){ return par[x] == x ? x : par[x] = find(par[x]);}void join(int x, int y){ x = find(x); y = find(y); if(x != y) par[x] = y; else ans ++;}int main(){ while(cin >> n >> m) { memset(sum, 0, sizeof sum); init(n); ans = 0; edge e[m]; for(int i = 0; i < m; i ++) { cin >> e[i].u >> e[i].v; sum[e[i].u] ++; sum[e[i].v] ++; } for(int i = 0; i < m; i ++) { if(sum[e[i].u] == 2 && sum[e[i].v] == 2) { join(e[i].u, e[i].v); } } cout << ans << endl; } return 0;}P1094 纪念品分组题目描述元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作。为使得参加晚会的同学所获得 的纪念品价值相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两件纪念品, 并且每组纪念品的价格之和不能超过一个给定的整数。为了保证在尽量短的时间内发完所有纪念品,乐乐希望分组的数目最少。你的任务是写一个程序,找出所有分组方案中分组数最少的一种,输出最少的分组数目。输入格式共n+2行:第1行包括一个整数w,为每组纪念品价格之和的上上限。第2行为一个整数n,表示购来的纪念品的总件数G。第3至n+2行每行包含一个正整数P_i(5 <= P_i <= w)表示所对应纪念品的价格。输出格式一个整数,即最少的分组数目。12345678910111213141516171819输入输出样例输入1009902020305060708090输出6说明/提示50%的数据满足:1 \le n \le 151≤n≤15100%的数据满足:1 \le n \le 30000,80 \le w \le 2001≤n≤30000,80≤w≤200题意:1很简单的一道贪心题,设一个"指针"l和r分别指向首和尾,首先排序,然后开始让a[l] + a[r] <= w的时候作为一组,l和r分别向后向前移一位,组数++,否则数组++,r--code:123456789101112131415161718192021222324252627282930313233343536373839404142#include<iostream>#include<stdio.h>#include<cstring>#include<algorithm>#include<cmath>#include<queue>#include<stack>#include<vector>#include<map>using namespace std;typedef long long ll;const int mod = 1e9 + 7;const int INF = 0x3f3f3f3f;const int maxx = 1e5;int a[maxx];int main(){ int n, w; cin >> w; cin >> n; for(int i = 0; i < n; i ++) cin >> a[i]; int ans = 0; sort(a, a + n); int l = 0, r = n - 1; while(l <= r) { if((a[l] + a[r]) <= w) { ans ++; l ++; r --; } else { ans ++; r --; } } cout << ans << '\n'; return 0;}CTF:一道来自Wargame.kr v2.1的SB题WTF_CODE进去之后题目是이게 진짜 소스코드라고? 아무것도 안보인다고!!is this source code really???? i can`t see anything really!然后你点击链接之后会让你下载一个文件,然后打开(用记事本就可以)之后你会发现里面什么都没有((艹皿艹 )),但是当你全选之后你会发现一个神奇的事情,全tm是空格是tab然后你可能就和我一样,人直接就傻了google一波后发现还有一个神奇的网站(艹皿艹 )严重怀疑这两个网站是一伙的,然后在最下面的选择语言里面有一个Whitespace,选择它然后复制并粘贴之前的一堆“答案”,Run。拉倒最下面,就能得到答案了]]></content>
<categories>
<category>ACM</category>
<category>CTF</category>
</categories>
<tags>
<tag>CTF</tag>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>review</tag>
<tag>并查集</tag>
<tag>贪心</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Rday20]]></title>
<url>%2F2019%2F10%2F17%2FRday20%2F</url>
<content type="text"><![CDATA[Rday20二分 + CTF入门Computer Game12345678910111213Vova is playing a computer game. There are in total n turns in the game and Vova really wants to play all of them. The initial charge of his laptop battery (i.e. the charge before the start of the game) is k.During each turn Vova can choose what to do:If the current charge of his laptop battery is strictly greater than a, Vova can just play, and then the charge of his laptop battery will decrease by a;if the current charge of his laptop battery is strictly greater than b (b<a), Vova can play and charge his laptop, and then the charge of his laptop battery will decrease by b;if the current charge of his laptop battery is less than or equal to a and b at the same time then Vova cannot do anything and loses the game.Regardless of Vova's turns the charge of the laptop battery is always decreases.Vova wants to complete the game (Vova can complete the game if after each of n turns the charge of the laptop battery is strictly greater than 0). Vova has to play exactly n turns. Among all possible ways to complete the game, Vova wants to choose the one where the number of turns when he just plays (first type turn) is the maximum possible. It is possible that Vova cannot complete the game at all.Your task is to find out the maximum possible number of turns Vova can just play (make the first type turn) or report that Vova cannot complete the game.You have to answer q independent queries.Input123The first line of the input contains one integer q (1≤q≤105) — the number of queries. Each query is presented by a single line.The only line of the query contains four integers k,n,a and b (1≤k,n≤109,1≤b<a≤109) — the initial charge of Vova's laptop battery, the number of turns in the game and values a and b, correspondingly.Output1For each query print one integer: -1 if Vova cannot complete the game or the maximum number of turns Vova can just play (make the first type turn) otherwise.1234567891011121314151617181920ExampleInput615 5 3 215 5 4 315 5 2 115 5 5 116 7 5 220 5 7 3Output4-15201NoteIn the first example query Vova can just play 4 turns and spend 12 units of charge and then one turn play and charge and spend 2 more units. So the remaining charge of the battery will be 1.In the second example query Vova cannot complete the game because even if he will play and charge the battery during each turn then the charge of the laptop battery will be 0 after the last turn.思路:给定四个数字 k, n, a, b, 其中 a > b,要求最大数 i 使得 i a + (n - i) b < n 成立code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071//二分解法#include<bits/stdc++.h>using namespace std;typedef long long ll;ll k, n, a, b;ll ans;bool slove(ll mid){ return mid*a + (n - mid) * b < k; }int main(){ ios::sync_with_stdio(false); ll t; cin >> t; while(t --) { cin >> k >> n >> a >> b; ll l = 0, r = n; ans = -1; while(l <= r) { ll mid = (l + r) / 2; if(slove(mid)) { l = mid + 1; ans = mid; } else { r = mid - 1; } } cout << ans << '\n'; } return 0;}//大佬的解法#include<bits/stdc++.h>using namespace std;int main(){ ll t; ios::sync_with_stdio(false); cin >> t; while(t --) { cin >> k >> n >> a >> b; ll ans = 0; k --; if(k / b < n) ans = -1; else { k -= n * b; a -= b; ans = min(n, k / a); } cout << ans << '\n'; } return 0;}Training: Regex (Training, Regex)123456789101112131415161718192021222324252627282930313233343536Level 1匹配一个空字符串,学习匹配匹配字符串开头结尾的两个符号:/^$/^ 匹配字符串的开始$ 匹配字符串的结束Level 2匹配”wechall”,/^wechall$/Level 3匹配以wechall或wechall4为文件名,并以.jpg/.gif/.tiff/.bmp/.png为后缀的图像,/^wechall4?\.(?:jpg|gif|tiff|bmp|png)$/? 重复零次或一次所以4?表示重复0次或1次4,也就是wechall和wechall4都可以匹配。\. 转义使用\来取消.字符的特殊意义,来显示.字符本身(?:jpg|gif|tiff|bmp|png)\(?:exp)表示非捕获分组,匹配exp,不捕获匹配的文本,也不给此分组分配组号。为什么要用(?:exp),而不用(exp)呢?因为直接提交/^wechall4?\.(jpg|gif|tiff|bmp|png)$/会报错:Your pattern would capture a string, but this is not wanted. Please use a non capturing group.您的模式将捕获一个字符串,但这是不需要的。请使用非捕获组。所以需要使用(?:exp)非捕获分组。至于(?:jpg|gif|tiff|bmp|png)\中的|表示分枝条件Level 4捕获文件名,需要对文件名添加捕获分组:/^(wechall4?)\.(?:jpg|gif|tiff|bmp|png)$/(wechall4?)用小括号来指定子表达式(也叫做分组),然后你就可以指定这个子表达式的重复次数了,你也可以对子表达式进行其它一些操作。]]></content>
<categories>
<category>ACM</category>
<category>CTF</category>
</categories>
<tags>
<tag>CTF</tag>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>review</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Rday12]]></title>
<url>%2F2019%2F09%2F28%2FRday12%2F</url>
<content type="text"><![CDATA[Rday12食物链待补动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。有人用两种说法对这N个动物所构成的食物链关系进行描述:第一种说法是”1 X Y”,表示X和Y是同类。第二种说法是”2 X Y”,表示X吃Y。此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。1) 当前的话与前面的某些真的话冲突,就是假话;2) 当前的话中X或Y比N大,就是假话;3) 当前的话表示X吃X,就是假话。你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。Input第一行是两个整数N和K,以一个空格分隔。以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。若D=1,则表示X和Y是同类。若D=2,则表示X吃Y。Output只有一个整数,表示假话的数目。1234567891011Sample Input100 71 101 12 1 22 2 32 3 31 1 32 3 11 5 5Sample Output3code:12]]></content>
<categories>
<category>ACM</category>
<category>review</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>review</tag>
<tag>并查集</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Rday11]]></title>
<url>%2F2019%2F09%2F27%2FRday11%2F</url>
<content type="text"><![CDATA[Rday11背包待补Cash MachineA Bank plans to install a machine for cash withdrawal. The machine is able to deliver appropriate @ bills for a requested cash amount. The machine uses exactly N distinct bill denominations, say Dk, k=1,N, and for each denomination Dk the machine has a supply of nk bills. For example,N=3, n1=10, D1=100, n2=4, D2=50, n3=5, D3=10means the machine has a supply of 10 bills of @100 each, 4 bills of @50 each, and 5 bills of @10 each.Call cash the requested amount of cash the machine should deliver and write a program that computes the maximum amount of cash less than or equal to cash that can be effectively delivered according to the available bill supply of the machine.Notes:@ is the symbol of the currency delivered by the machine. For instance, @ may stand for dollar, euro, pound etc.InputThe program input is from standard input. Each data set in the input stands for a particular transaction and has the format:cash N n1 D1 n2 D2 … nN DNwhere 0 <= cash <= 100000 is the amount of cash requested, 0 <=N <= 10 is the number of bill denominations and 0 <= nk <= 1000 is the number of available bills for the Dk denomination, 1 <= Dk <= 1000, k=1,N. White spaces can occur freely between the numbers in the input. The input data are correct.OutputFor each set of data the program prints the result to the standard output on a separate line as shown in the examples below.1234567891011121314151617Sample Input735 3 4 125 6 5 3 350633 4 500 30 6 100 1 5 0 1735 00 3 10 100 10 50 10 10Sample Output73563000HintThe first data set designates a transaction where the amount of cash requested is @735. The machine contains 3 bill denominations: 4 bills of @125, 6 bills of @5, and 3 bills of @350. The machine can deliver the exact amount of requested cash.In the second case the bill supply of the machine does not fit the exact amount of cash requested. The maximum cash that can be delivered is @630. Notice that there can be several possibilities to combine the bills in the machine for matching the delivered cash.In the third case the machine is empty and no cash is delivered. In the fourth case the amount of cash requested is @0 and, therefore, the machine delivers no cash.题意:多重背包code:12InvestmentJohn never knew he had a grand-uncle, until he received the notary’s letter. He learned that his late grand-uncle had gathered a lot of money, somewhere in South-America, and that John was the only inheritor.John did not need that much money for the moment. But he realized that it would be a good idea to store this capital in a safe place, and have it grow until he decided to retire. The bank convinced him that a certain kind of bond was interesting for him.This kind of bond has a fixed value, and gives a fixed amount of yearly interest, payed to the owner at the end of each year. The bond has no fixed term. Bonds are available in different sizes. The larger ones usually give a better interest. Soon John realized that the optimal set of bonds to buy was not trivial to figure out. Moreover, after a few years his capital would have grown, and the schedule had to be re-evaluated.Assume the following bonds are available:Value|Annual interest4000|4003000|250With a capital of e10 000 one could buy two bonds of $4 000, giving a yearly interest of $800. Buying two bonds of $3 000, and one of $4 000 is a better idea, as it gives a yearly interest of $900. After two years the capital has grown to $11 800, and it makes sense to sell a $3 000 one and buy a $4 000 one, so the annual interest grows to $1 050. This is where this story grows unlikely: the bank does not charge for buying and selling bonds. Next year the total sum is $12 850, which allows for three times $4 000, giving a yearly interest of $1 200.Here is your problem: given an amount to begin with, a number of years, and a set of bonds with their values and interests, find out how big the amount may grow in the given period, using the best schedule for buying and selling bonds.InputThe first line contains a single positive integer N which is the number of test cases. The test cases follow.The first line of a test case contains two positive integers: the amount to start with (at most $1 000 000), and the number of years the capital may grow (at most 40).The following line contains a single number: the number d (1 <= d <= 10) of available bonds.The next d lines each contain the description of a bond. The description of a bond consists of two positive integers: the value of the bond, and the yearly interest for that bond. The value of a bond is always a multiple of $1 000. The interest of a bond is never more than 10% of its value.OutputFor each test case, output – on a separate line – the capital at the end of the period, after an optimal schedule of buying and selling.12345678Sample Input110000 424000 4003000 250Sample Output14050题意:完全背包code:12]]></content>
<categories>
<category>ACM</category>
<category>review</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>review</tag>
<tag>背包</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Rday10]]></title>
<url>%2F2019%2F09%2F26%2FRday10%2F</url>
<content type="text"><![CDATA[Rday10FBI树待补FBI树链接题目描述我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全“1”串称为I串,既含“0”又含“1”的串则称为F串。FBI树是一种二叉树1,它的结点类型也包括F结点,B结点和I结点三种。由一个长度为2N的“01”串S可以构造出一棵FBI树T,递归的构造方法如下:1) T的根结点为R,其类型与串S的类型相同;2) 若串S的长度大于1,将串S从中间分开,分为等长的左右子串S1和S2;由左子串S1构造R的左子树T1,由右子串S2构造R的右子树T2。现在给定一个长度为2N的“01”串,请用上述构造方法构造出一棵FBI树,并输出它的后序遍历2序列。1) 二叉树:二叉树是结点的有限集合,这个集合或为空集,或由一个根结点和两棵不相交的二叉树组成。这两棵不相交的二叉树分别称为这个根结点的左子树和右子树。2) 后序遍历:后序遍历是深度优先遍历二叉树的一种方法,它的递归定义是:先后序遍历左子树,再后序遍历右子树,最后访问根。输入描述:第一行是一个整数N(0 <= N <= 10)第二行是一个长度为2N的“01”串。输出描述:一个字符串,即FBI树的后序遍历序列。123456示例1输入310001011输出IBFBBBFIBFIIIFF备注:对于40%的数据,N <= 2;对于全部的数据,N<= 10。]]></content>
<categories>
<category>ACM</category>
<category>review</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>review</tag>
<tag>树</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Rday9]]></title>
<url>%2F2019%2F09%2F25%2FRday9%2F</url>
<content type="text"><![CDATA[Rday9贪心Gathering ChildrenGiven is a string S consisting of L and R.Let N be the length of S. There are N squares arranged from left to right, and the i-th character of S from the left is written on the i-th square from the left.The character written on the leftmost square is always R, and the character written on the rightmost square is always L.Initially, one child is standing on each square.Each child will perform the move below 10^{100} times:Move one square in the direction specified by the character written in the square on which the child is standing. L denotes left, and R denotes right.Find the number of children standing on each square after the children performed the moves.ConstraintsS is a string of length between 2 and 10^5 (inclusive).Each character of S is L or R.The first and last characters of S are R and L, respectively.InputInput is given from Standard Input in the following format:SOutputPrint the number of children standing on each square after the children performed the moves, in order from left to right.123456789101112131415Sample Input 1RRLRLSample Output 10 1 2 1 1After each child performed one move, the number of children standing on each square is 0, 2, 1, 1, 1 from left to right.After each child performed two moves, the number of children standing on each square is 0, 1, 2, 1, 1 from left to right.After each child performed 10^{100} moves, the number of children standing on each square is 0, 1, 2, 1, 1 from left to right.Sample Input 2RRLLLLRLRRLLSample Output 20 3 3 0 0 0 1 1 0 2 2 0Sample Input 3RRRLLRLLRRRLLLLLSample Output 30 0 3 2 0 2 1 0 0 0 4 4 0 0 0 0题解:题意就是给一个R开头L结尾只包括R和L的字符串,然后有字符串长的广场,每个广场一个小孩,每个小孩需要按照地标走(地标就是当前位置的字符,R向右,L向左),问你走10^100次后每个广场的孩子人数。我觉得是一道思维题,模拟几遍后发现只有在RL的交界处才会有孩子,而当一个子集(例如RRRRLL)中如果R+L是偶数,那么就把和平分到最后一个R和第一个L。如果是奇数就需要找到是R最后大还是L最后大了。123456R R L R R R L L R R R R R L L 0: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1: 0 2 1 0 1 2 2 0 0 1 1 1 2 2 0 2: 0 1 2 0 0 3 2 0 0 0 1 1 3 2 0 3: 0 2 1 0 0 2 3 0 0 0 0 1 3 3 0 4: 0 1 2 0 0 3 2 0 0 0 0 0 4 3 0由此我们可以发现,当r > l && (r - l)%2 == 1 时,如果l%2 == 0,r比l大1;否则l比r大1。同理可推到l > r的情况。code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869#include<bits/stdc++.h>using namespace std;typedef long long ll;const int mod = 1e9 + 7;const int INF = 0x3f3f3f3f;const int maxx = 1e5;int ans[maxx];int main(){ string s; cin >> s; int len = s.size(); int l, r; for(int i = 0; i < len; i ++) { l = 0, r = 0; if(s[i] == 'R') { r ++; int x, y; for(int j = i + 1; j < len; j ++) { if(s[j] == 'R') r ++; else { x = j; break; } } for(int j = x; j < len; j ++) { if(s[j] == 'L') l ++; if(s[j] == 'R' || j == len - 1) { ans[x] = ans[x - 1] = (l + r) / 2; if(r > l && (r - l) % 2 == 1) { if(l % 2 == 1) ans[x] ++; else ans[x - 1] ++; } else if(l > r && (l - r) % 2 == 1) { if(r % 2 == 1) ans[x - 1] ++; else ans[x] ++; } y = j; break; } } i = y - 1; if(y == len - 1) i ++; } } for(int i = 0; i < len; i ++) { cout << ans[i]; if(i < len - 1) cout << ' '; else cout << '\n'; } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>review</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>review</tag>
<tag>贪心</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Rday8]]></title>
<url>%2F2019%2F09%2F24%2FRday8%2F</url>
<content type="text"><![CDATA[Rday8BFSCatch him在美式足球中,四分卫负责指挥整只球队的进攻战术和跑位,以及给接球员传球的任务。四分卫是一只球队进攻组最重要的球员,而且一般身体都相对比较弱小,所以通常球队会安排5-7名大汉来保护他,其中站在四分卫前方、排成一线的5名球员称为进攻锋线,他们通常都是135公斤左右的壮汉。对防守方来说,攻击对手的四分卫当然是最直接的限制对手进攻的方法。如果效果好,就可以在对方四分卫传球之前将其按翻在地,称之为擒杀。擒杀是最好的鼓舞防守队士气的方法,因为对方连传球的机会都没有,进攻就结束了,还必须倒退一些距离开球。凶狠的擒杀甚至能够将对方的四分卫弄伤,从而迫使对方更换这个进攻核心。在本题中,输入给出准备擒杀四分卫的防守球员的位置、对方每个进攻锋线球员的位置以及对方四分卫的位置,你的任务是求出这名准备擒杀的防守球员至少要移动多少步,才能够擒杀对方四分卫。假设对方进攻锋线和四分卫在这个过程中都不会移动。只有1名防守球员,防守球员只要碰到对方四分卫就算擒杀。所有的球员都是一块连续的、不中空的2维区域。防守球员不可以从进攻锋线的身体上穿过,也不可以从界外穿过(只能走空地)。防守队员不可以转动身体,只能平移。防守队员的身体所有部分向同一个方向(上、下、左、右)移动1格的过程叫做1步。Input12输入包含多组数据。每组数据第一行都是两个整数H,W(0<H,W<=100),表示整个区域的高度和宽度,H=W=0表示输入结束。接下来有H行,每行W个字符。每个字符如果是’.’,表示这里是空地,如果是’O’,表示是进攻锋线队员的身体,如果是’D’,表示是准备擒杀的防守球员的身体,如果是’Q’,表示是四分卫的身体。输入保证符合上面的条件。防守球员的身体总共不超过20格。Output对每组数据,输出包含擒杀所需最少步数的一行。如果不能擒杀,输出带’Impossible’的一行。12345678910111213141516171819202122Sample Input6 6.Q....QQ..OO.OO..O...O.OOO.O......DD7 7.Q.....QQ.OOO....O...O......OO..OO..O..........DD0 0Sample OutputImpossible9题意:首先我们移动的是一个由好多格子或者单个格子组成的一个D(防守队员)。如果我们每一个点都进行移动的话未免有点太尴尬,而且vis[][]判断是否走过该点的判断也不是很好写,这个时候我们需要一个抽象的想法:我们把这一坨D的最先出现的D(两层for遍历的情况下)当做一个头,我们移动头即可,那么我们怎样细节上处理这个题目呢?如果我们有了一个标尺:“头” 之后呢,我们vis【】【】数组也就好处理了,对于头走过的点,标记上即可,那么他的身子要怎样移动呢?我们都学过一个名词叫做:“相对”,关系可以相对,力可以相对,那么位子也可以相对。对于这样的一个图:ODOODOODD我们规定第一个出现的D也就是坐标为(0,1)的点作为这个一坨D的头,我们可以通过头这样找到其他的身体部分:(0,1)+(1,0)=(1,1)找到第二个出现的D,(0,1)+(2,0)=(2,1)找到第三个出现的D,(0,1)+(2,1)=(2,2)找到最后一个D。那么我们可以通过保存(1,0)(2,0)(2,1)这三个x,y的相对位子值来通过“头”找到他们的身子。这个时候小问题处理完毕了,我们就可以确定答题思路了:用头漫无目的的BFS,每一次找到一个能走的位子都判断一下身子能否也可以达到相对位子,当然我们的“头”找到了Q的时候不要直接输出步数,我们还要判断他的身子能否走到合法的位子。同理,如果“身子”找到了Q的时候也不要直接输出步数,我们要确定所有身子的组成都能走到合法的位子才行code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125#include<bits/stdc++.h>using namespace std;typedef long long ll;const int mod = 1e9 + 7;const int INF = 0x3f3f3f3f;const int maxx = 1e3;struct node{ int x, y, step;}now, nex;int n, m;int cnt;int fang[25][2];char a[maxx][maxx];int vis[maxx][maxx];int d[4][2] = { 1, 0, -1, 0, 0, 1, 0, -1};void bfs(int x, int y){ memset(vis, 0, sizeof vis); vis[x][y] = 1; queue<node> q; now.x = x; now.y = y; now.step = 0; q.push(now); while(!q.empty()) { now = q.front(); q.pop(); for(int i = 0; i < 4; i ++) { nex.x = now.x + d[i][0]; nex.y = now.y + d[i][1]; if(nex.x >= 0 && nex.y >= 0 && nex.x < n && nex.y < m && vis[nex.x][nex.y] == 0 && a[nex.x][nex.y] != 'O') { //找到头部 if(a[nex.x][nex.y] == 'Q') { int flag = 1; //找头部附近的其他身体部分 并且判断是否合法 for(int j = 0; j < cnt; j ++) { int xx = nex.x + fang[j][0]; int yy = nex.y + fang[j][1]; if(xx >= 0 && yy >= 0 && xx < n && yy < m && a[xx][yy] != 'O') continue; flag = 0;//不合法 } if(flag) { cout << now.step + 1 << '\n'; return ; } } int flag = 1; int flag1 = 0; for(int j = 0; j < cnt; j ++) { int xx = nex.x + fang[j][0]; int yy = nex.y + fang[j][1]; //如果某个身子的部分碰到了Q,这个时候不要break,也要继续判断其他身子是否合法。 if(xx >= 0 && yy >= 0 && xx < n && yy < m && a[xx][yy] == 'Q') flag1 = 1; if(xx >= 0 && yy >= 0 && xx < n && yy < m && a[xx][yy] != 'O') continue; flag = 0; } if(flag == 1 && flag1 == 1) { cout << now.step + 1 << '\n'; return ; } if(flag) { vis[nex.x][nex.y] = 1; nex.step = now.step + 1; q.push(nex); } } } } printf("Impossible\n");}int main(){ while(~scanf("%d %d",&n, &m)) { if(n == 0 && m == 0) break; cnt = 0; int sx, sy; for(int i = 0; i < n; i ++) { scanf("%s",a[i]); for(int j = 0; j < m; j ++) { if(a[i][j] == 'D') { //找到头 if(cnt == 0) { sx = i; sy = j; cnt = 1; } else { //记录身体的其他部分 fang[cnt][0] = i - sx; fang[cnt][1] = j - sy; cnt ++; } } } } bfs(sx, sy); } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>review</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>review</tag>
<tag>BFS</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Rday7]]></title>
<url>%2F2019%2F09%2F23%2FRday7%2F</url>
<content type="text"><![CDATA[Rday7单调栈单调栈定义:单调栈,顾名思义,是栈内元素保持一定单调性(单调递增或单调递减)的栈。这里的单调递增或递减是指的从栈顶到栈底单调递增或递减。既然是栈,就满足后进先出的特点。与之相对应的是单调队列。实现:例如实现一个单调递增的栈,比如现在有一组数10,3,7,4,12。从左到右依次入栈,则如果栈为空或入栈元素值小于栈顶元素值,则入栈;否则,如果入栈则会破坏栈的单调性,则需要把比入栈元素小的元素全部出栈。单调递减的栈反之。10入栈时,栈为空,直接入栈,栈内元素为10。3入栈时,栈顶元素10比3大,则入栈,栈内元素为10,3。7入栈时,栈顶元素3比7小,则栈顶元素出栈,此时栈顶元素为10,比7大,则7入栈,栈内元素为10,7。4入栈时,栈顶元素7比4大,则入栈,栈内元素为10,7,4。12入栈时,栈顶元素4比12小,4出栈,此时栈顶元素为7,仍比12小,栈顶元素7继续出栈,此时栈顶元素为10,仍比12小,10出栈,此时栈为空,12入栈,栈内元素为12。伪代码123456789101112131415161718192021/** 本伪代码对应的是单调递减栈*共n个元素,编号为0~n-1*/while(栈为空) 栈顶元素出栈; //先清空栈a[n]=-1;for(i=0;i<=n;i++){ if(栈为空或入栈元素大于等于栈顶元素) 入栈; else { while(栈非空并且栈顶元素大于等于入栈元素) { 栈顶元素出栈; 更新结果; } 将最后一次出栈的栈顶元素(即当前元素可以拓展到的位置)入栈; 更新最后一次出栈的栈顶元素其对应的值; }}输出结果;应用:以上就是一个单调栈的定义及其实现,下面就来说一下它可以解决哪些问题。碰到问题时就需要灵活运用了。1.最基础的应用就是给定一组数,针对每个数,寻找它和它右边第一个比它大的数之间有多少个数。2.给定一序列,寻找某一子序列,使得子序列中的最小值乘以子序列的长度最大。3.给定一序列,寻找某一子序列,使得子序列中的最小值乘以子序列所有元素和最大。Bad Hair DaySome of Farmer John’s N cows (1 ≤ N ≤ 80,000) are having a bad hair day! Since each cow is self-conscious about her messy hairstyle, FJ wants to count the number of other cows that can see the top of other cows’ heads.Each cow i has a specified height hi (1 ≤ hi ≤ 1,000,000,000) and is standing in a line of cows all facing east (to the right in our diagrams). Therefore, cow i can see the tops of the heads of cows in front of her (namely cows i+1, i+2, and so on), for as long as these cows are strictly shorter than cow i.Consider this example:= = == - = Cows facing right –>= = == - = = == = = = = =1 2 3 4 5 6Cow#1 can see the hairstyle of cows #2, 3, 4Cow#2 can see no cow’s hairstyleCow#3 can see the hairstyle of cow #4Cow#4 can see no cow’s hairstyleCow#5 can see the hairstyle of cow 6Cow#6 can see no cows at all!Let ci denote the number of cows whose hairstyle is visible from cow i; please compute the sum of c1 through cN.For this example, the desired is answer 3 + 0 + 1 + 0 + 1 + 0 = 5.InputLine 1: The number of cows, N.Lines 2..N+1: Line i+1 contains a single integer that is the height of cow i.OutputLine 1: A single integer that is the sum of c 1 through cN.12345678910Sample Input610374122Sample Output5题意:也就是说针对每只牛,啊,不,每头牛求它到它右边第一个比它高(或身高相等)的牛之间有多少头牛,然后将求得的结果相加就是最后的答案。朴素的做法是针对每头牛去寻找右边比它高的牛的位置,时间复杂度为O(n^2),如果用单调栈的话就是O(n).利用根据单调递增栈解决,如果栈为空或入栈元素小于栈顶元素则入栈,否则会破坏栈的单调性,则将栈顶元素出栈并更新结果,直到栈为空或碰到一个小于入栈元素的值。然后将当前元素入栈。设数组的最后一个元素为最大值,也就相当于在最右边的牛的右边设了一个高度无限高的牛。这样做的目的是,最后让栈内的元素全部出栈。PS:代码中的单调栈保存的是牛的位置。结果应该用long long 型,最多有80000头牛,每头牛右边最多有80000头牛,8000080000=6.410^9,而int最多表示大约为2*10^9……code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<stack>#include<stdio.h>//#include<bits/stdc++.h>using namespace std;typedef long long ll;const int mod = 1e9 + 7;const int INF = 0x3f3f3f3f;const int maxx = 1e5;int a[maxx], n, top;int main(){ int n; while(~scanf("%d",&n)) { stack<int> s; ll ans = 0; while(!s.empty()) s.pop(); for(int i = 0; i < n; i ++) cin >> a[i]; a[n] = INF; for(int i = 0; i <= n; i ++) { //如果栈为空或入栈元素小于栈顶元素,则入栈 if(s.empty() || a[i] < a[s.top()]) s.push(i); else { //如果栈不为空并且栈顶元素不大于入栈元素,则将栈顶元素出栈 while(!s.empty() && a[i] >= a[s.top()]) { //获取栈顶元素 top = s.top(); //栈顶元素出栈 s.pop(); //两坐标之差减去一 ans += (i - top - 1);// cout << i << " " << top << " " << ans << '\n'; } //当前元素入栈,为了不影响坐标位置 s.push(i); } } cout << ans << '\n'; } return 0;}Largest Rectangle in a HistogramA histogram is a polygon composed of a sequence of rectangles aligned at a common base line. The rectangles have equal widths but may have different heights. For example, the figure on the left shows the histogram that consists of rectangles with the heights 2, 1, 4, 5, 1, 3, 3, measured in units where 1 is the width of the rectangles:Usually, histograms are used to represent discrete distributions, e.g., the frequencies of characters in texts. Note that the order of the rectangles, i.e., their heights, is important. Calculate the area of the largest rectangle in a histogram that is aligned at the common base line, too. The figure on the right shows the largest aligned rectangle for the depicted histogram.InputThe input contains several test cases. Each test case describes a histogram and starts with an integer n, denoting the number of rectangles it is composed of. You may assume that 1<=n<=100000. Then follow n integers h1,…,hn, where 0<=hi<=1000000000. These numbers denote the heights of the rectangles of the histogram in left-to-right order. The width of each rectangle is 1. A zero follows the input for the last test case.OutputFor each test case output on a single line the area of the largest rectangle in the specified histogram. Remember that this rectangle must be aligned at the common base line.123456789Sample Input7 2 1 4 5 1 3 34 1000 1000 1000 10000Sample Output84000HintHuge input, scanf is recommended.题意:对于每个矩形,我们求出它向左向右分别能延伸的长度,然后乘以它的高度,这就是以当前矩形为最低高度可以得到的最大的面积。只需要求个最大值即可。总结性的来说就是:给定一序列,寻找某一子序列,使得子序列中的最小值乘以子序列的长度最大。这是单调栈的一种应用。构造一个单调递减的单调栈,如果栈为空或入栈元素大于等于栈顶元素则入栈,否则会破坏栈的单调性,将大于入栈元素的栈顶元素出栈,直到栈为空或遇到一个小于等于入栈元素的元素。然后将最后一次出栈的栈顶元素向左向右延伸,也就是确定以栈顶元素的高度为最低高度的矩形的宽度,改变其对应的值,然后入栈。并且将数组最后一个元素设为最小值,以最后清空栈内所有元素。注意:1.单调栈保存的是每个矩形的编号,也就是位置。2.在维护单调栈,也就是每个矩形向左向右延伸的过程中会使原来数组的值改变。3.数据很大,要用long long型。4.最后一次出栈的栈顶元素就是当前入栈元素可以向左拓展到的最大距离。code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455#include<iostream>#include<cstring>#include<algorithm>#include<stdio.h>#include<cmath>#include<stack>#include<queue>using namespace std;typedef long long ll;const int mod = 1e9 + 7;const int INF = 0x3f3f3f3f;const int maxx = 1e5 + 7;int flag;ll a[maxx], n;int main(){ ll ans, tem = 0; stack<int> s; while(~scanf("%lld",&n)) { if(n == 0) break; while(!s.empty()) s.pop(); memset(a, 0, sizeof a); ans = 0; for(int i = 0; i < n; i ++) scanf("%lld",&a[i]); a[n] = -1;//清空栈 for(int i = 0; i <= n; i ++) { //如果栈为空或者入栈元素大于等于栈顶元素,入栈 if(s.empty() || a[i] >= a[s.top()]) s.push(i); else { //如果栈不为空并且入栈元素比栈顶元素小的时候才能更新面积 while(!s.empty() && a[i] < a[s.top()]) { //标记栈顶元素 flag = s.top(); s.pop(); //出栈过程中计算面积 tem = (i - flag) * a[flag]; ans = max(ans, tem); } //只将可以延伸到的最左端的位置入栈 s.push(flag); //并修改该位置的值 a[flag] = a[i]; } } printf("%lld\n",ans); } return 0;}Feel GoodDescriptionBill is developing a new mathematical theory for human emotions. His recent investigations are dedicated to studying how good or bad days influent people’s memories about some period of life.A new idea Bill has recently developed assigns a non-negative integer value to each day of human life.Bill calls this value the emotional value of the day. The greater the emotional value is, the better the daywas. Bill suggests that the value of some period of human life is proportional to the sum of the emotional values of the days in the given period, multiplied by the smallest emotional value of the day in it. This schema reflects that good on average period can be greatly spoiled by one very bad day.Now Bill is planning to investigate his own life and find the period of his life that had the greatest value. Help him to do so.InputThe first line of the input contains n - the number of days of Bill’s life he is planning to investigate(1 <= n <= 100 000). The rest of the file contains n integer numbers a1, a2, … an ranging from 0 to 106 - the emotional values of the days. Numbers are separated by spaces and/or line breaks.OutputPrint the greatest value of some period of Bill’s life in the first line. And on the second line print two numbers l and r such that the period from l-th to r-th day of Bill’s life(inclusive) has the greatest possible value. If there are multiple periods with the greatest possible value,then print any one of them.123456Sample Input63 1 6 4 5 2Sample Output603 5题意:求序列中的最小值乘以这个序列的和的值最大,是典型的单调栈的应用。一般的思路是求每个数字所在的能使其值为区间最小值的最大区间,然后求出区间元素和乘以该值并更新结果的最大值。普通的做法时间复杂度为O(n^2),用单调栈可以达到O(n)。用一个单调递减栈,如果栈为空或入栈元素大于等于栈顶元素,则入栈,否则将破坏栈的单调性,则将栈顶元素出栈,直到栈为空或碰到第一个小于等于入栈元素的元素。然后将最后一次出栈的栈顶元素入栈,并将其向左右拓展,并更新其对应的值。由于维护单调栈会改变原数组的值,同时为了方便求区间元素值,我们设置一个sum数组,记录前缀和。我们将原数组的最后一个值设为最小值,以方便最后将栈内所有元素出栈。code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758#include<iostream>#include<cstring>#include<algorithm>#include<stdio.h>#include<cmath>#include<stack>#include<queue>using namespace std;typedef long long LL;int main(){ //pos1和pos2记录区间的开始和结束位置 int i,n,pos1,pos2; //tmp为临时变量,记录区间内的和;top指向栈顶元素;ans为结果;sum为前缀和 LL tmp,top,ans,a[100010],sum[100010]; stack<int> st; //单调栈,记录元素位置 while(~scanf("%d",&n)) { while(!st.empty()) st.pop(); //清空栈 sum[0]=0; for(i=1;i<=n;i++) { scanf("%lld",&a[i]); sum[i]=sum[i-1]+a[i]; //计算前缀和 } a[n+1]=-1; //将最后一个设为最小值,以最后让栈内元素全部出栈 ans=0; for(i=1;i<=n+1;i++) { if(st.empty()||a[i]>=a[st.top()]) { //如果栈为空或入栈元素大于等于栈顶元素,则入栈 st.push(i); } else { while(!st.empty()&&a[i]<a[st.top()]) { //如果栈非空并且入栈元素小于栈顶元素,则将栈顶元素出栈 top=st.top(); st.pop(); tmp=sum[i-1]-sum[top-1]; //计算区间内元素和 tmp*=a[top]; //计算结果 if(tmp>=ans) { //更新最大值并记录位置 ans=tmp; pos1=top; pos2=i; } } st.push(top); //将最后一次出栈的栈顶元素入栈 a[top]=a[i]; //将其向左向右延伸并更新对应的值 } } printf("%lld\n",ans); printf("%d %d\n",pos1,pos2-1); } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>review</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>review</tag>
<tag>单调栈</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Rday6]]></title>
<url>%2F2019%2F09%2F22%2FRday6%2F</url>
<content type="text"><![CDATA[Rday6小比赛Connecting VerticesThere are n points marked on the plane. The points are situated in such a way that they form a regular polygon (marked points are its vertices, and they are numbered in counter-clockwise order). You can draw n - 1 segments, each connecting any two marked points, in such a way that all points have to be connected with each other (directly or indirectly).But there are some restrictions. Firstly, some pairs of points cannot be connected directly and have to be connected undirectly. Secondly, the segments you draw must not intersect in any point apart from the marked points (that is, if any two segments intersect and their intersection is not a marked point, then the picture you have drawn is invalid).How many ways are there to connect all vertices with n - 1 segments? Two ways are considered different iff there exist some pair of points such that a segment is drawn between them in the first way of connection, but it is not drawn between these points in the second one. Since the answer might be large, output it modulo 109 + 7.InputThe first line contains one number n (3 ≤ n ≤ 500) — the number of marked points.Then n lines follow, each containing n elements. ai, j (j-th element of line i) is equal to 1 iff you can connect points i and j directly (otherwise ai, j = 0). It is guaranteed that for any pair of points ai, j = aj, i, and for any point ai, i = 0.OutputPrint the number of ways to connect points modulo 109 + 7.1234567891011121314151617181920212223ExamplesInput30 0 10 0 11 1 0Output1Input40 1 1 11 0 1 11 1 0 11 1 1 0Output12Input30 0 00 0 10 1 0Output0题解:题解:区间dpdpf[i][j]f[i][j]表示ii到jj有边且构成树的方案数g[i][j]g[i][j]表示ii到jj无边且构成树的方案数转移:枚举i,ji,j左右端点,kk是断点f[i][j]+=∑j−1k=i(f[i][k]+g[i][k])∗(f[k+1][j]+g[k+1][j])f[i][j]+=∑k=ij−1(f[i][k]+g[i][k])∗(f[k+1][j]+g[k+1][j])g[i][j]+=∑j−1k=i+1f[k][j]∗(f[i][k]+g[i][k])g[i][j]+=∑k=i+1j−1f[k][j]∗(f[i][k]+g[i][k])初始化只要f[i][j]=1f[i][j]=1就可以了code:123456789101112131415161718192021222324252627#include <cstdio>#define ll long longusing namespace std;const int N=1005,mod=1e9+7;int n;ll a[N][N],f[N][N],g[N][N];int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&a[i][j]); for(int i=1;i<=n;i++)f[i][i]=1; for(int len=2;len<=n;len++) for(int i=1;i+len-1<=n;i++) { int j=i+len-1; for(int k=i;k<j;k++) if(a[i][j]) f[i][j]=(f[i][j]+(f[i][k]+g[i][k])*(f[k+1][j]+g[k+1][j])%mod)%mod; for(int k=i+1;k<j;k++) if(a[k][j]) g[i][j]=(g[i][j]+f[k][j]*(f[i][k]+g[i][k])%mod)%mod; } printf("%lld\n",(f[1][n]+g[1][n])%mod); return 0;}Local ExtremaYou are given an array a. Some element of this array ai is a local minimum iff it is strictly less than both of its neighbours (that is, ai < ai - 1 and ai < ai + 1). Also the element can be called local maximum iff it is strictly greater than its neighbours (that is, ai > ai - 1 and ai > ai + 1). Since a1 and an have only one neighbour each, they are neither local minima nor local maxima.An element is called a local extremum iff it is either local maximum or local minimum. Your task is to calculate the number of local extrema in the given array.InputThe first line contains one integer n (1 ≤ n ≤ 1000) — the number of elements in array a.The second line contains n integers a1, a2, …, an (1 ≤ ai ≤ 1000) — the elements of array a.OutputPrint the number of local extrema in the given array.1234567891011ExamplesInput31 2 3Output0Input41 5 2 5Output2题解:签到题,按照题意写就行了code:123456789101112131415161718192021222324#include<bits/stdc++.h>using namespace std;const int maxx = 1e5;int a[maxx];int main(){ int t; while(scanf("%d",&t)!=EOF) { memset(a, 0, sizeof a); int ans = 0; for(int i = 0; i < t; i ++) cin >> a[i]; for(int i = 1; i < t - 1; i ++) { if(((a[i] < a[i - 1]) && (a[i] < a[i + 1])) || ((a[i] > a[i - 1]) && (a[i] > a[i + 1]))) { ans ++; } } cout << ans << '\n'; } return 0;}Xor-MSTYou are given a complete undirected graph with n vertices. A number ai is assigned to each vertex, and the weight of an edge between vertices i and j is equal to ai xor aj.Calculate the weight of the minimum spanning tree in this graph.InputThe first line contains n (1 ≤ n ≤ 200000) — the number of vertices in the graph.The second line contains n integers a1, a2, …, an (0 ≤ ai < 230) — the numbers assigned to the vertices.OutputPrint one number — the weight of the minimum spanning tree in the graph.1234567891011ExamplesInput51 2 3 4 5Output8Input41 2 3 4Output8题意:不妨从高到低贪心,我们把最高位按01分开两半分治,跨越两半的就在trie上贪心,这样做是O(nlog2n)O(n\log^2n)O(nlog 2n)的dalao’s code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283#include <stdio.h>#include <string.h>#include <algorithm>#include <vector>#include <math.h>#define rep(i,st,ed) for (int i=st;i<=ed;++i)#define drp(i,st,ed) for (int i=st;i>=ed;--i)#define copy(x,t) memcpy(x,t,sizeof(x))typedef long long LL;const LL INF=2147483647;const int N=200005;int rec[N*35][2],size[N*35],tot;int a[N],s[N];std:: vector <int> v1,v2;LL ans;int read() { int x=0,v=1; char ch=getchar(); for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar()); for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar()); return x*v;}void ins(int v) { int x=1; drp(i,29,0) { size[x]++; int tar=(v>>i)&1; if (!rec[x][tar]) { rec[x][tar]=++tot; rec[tot][0]=rec[tot][1]=0; size[tot]=0; } x=rec[x][tar]; } size[x]++;}LL ask(int v) { LL res=0; int x=1; drp(i,29,0) { int tar=(v>>i)&1; if (size[rec[x][tar]]) { x=rec[x][tar]; } else { x=rec[x][!tar]; res+=(1LL<<i); } } return res;}void solve(int l,int r,int p) { if (l>=r||p<0) return ; rep(i,l,r) if ((a[s[i]]>>p)&1) { v1.push_back(s[i]); } else v2.push_back(s[i]); for (int i=0;i<v1.size();++i) s[l+i]=v1[i]; int mid=v1.size()+l; for (int i=0;i<v2.size();++i) s[mid+i]=v2[i]; tot=1; rec[1][0]=rec[1][1]=0; rep(i,l,mid-1) ins(a[s[i]]); LL mn=INF; rep(i,mid,r) mn=std:: min(mn,ask(a[s[i]])); if (v1.size()&&v2.size()) ans+=mn; v1.clear(); v2.clear(); solve(l,mid-1,p-1); solve(mid,r,p-1);}int main() { int n=read(),mx=0; rep(i,1,n) { a[i]=read(); mx=std:: max(mx,(int)log2(a[i])); s[i]=i; } solve(1,n,mx); printf("%lld\n", ans); return 0;}Buggy RobotIvan has a robot which is situated on an infinite grid. Initially the robot is standing in the starting cell (0, 0). The robot can process commands. There are four types of commands it can perform:U — move from the cell (x, y) to (x, y + 1);D — move from (x, y) to (x, y - 1);L — move from (x, y) to (x - 1, y);R — move from (x, y) to (x + 1, y).Ivan entered a sequence of n commands, and the robot processed it. After this sequence the robot ended up in the starting cell (0, 0), but Ivan doubts that the sequence is such that after performing it correctly the robot ends up in the same cell. He thinks that some commands were ignored by robot. To acknowledge whether the robot is severely bugged, he needs to calculate the maximum possible number of commands that were performed correctly. Help Ivan to do the calculations!InputThe first line contains one number n — the length of sequence of commands entered by Ivan (1 ≤ n ≤ 100).The second line contains the sequence itself — a string consisting of n characters. Each character can be U, D, L or R.OutputPrint the maximum possible number of commands from the sequence the robot could perform to end up in the starting cell.12345678910111213141516ExamplesInput4LDUROutput4Input5RRRUUOutput0Input6LLRRRROutput4题意:最大能够执行的命令数量code:12345678910111213141516171819202122232425262728#include<bits/stdc++.h>using namespace std;const int maxx = 1e5;int main(){ ios::sync_with_stdio(false); int t, maxnum = 0; char c; cin >> t; int flag = 0; int x = 0, y = 0, ans = 0; int ans1 = 0, ans2 = 0, ans3 = 0, ans4 = 0; for(int i = 0; i < t; i ++) { cin >> c; if(c == 'L') ans1 ++; else if(c == 'R') ans2 ++; else if(c == 'U') ans3 ++; else ans4 ++; } int min1 = min(ans1, ans2); int min2 = min(ans3, ans4); ans = (min1 + min2) * 2; if(min1 != 0 || min2 != 0) cout << ans << '\n'; else puts("0"); return 0;}K-Dominant CharacterYou are given a string s consisting of lowercase Latin letters. Character c is called k-dominant iff each substring of s with length at least k contains this character c.You have to find minimum k such that there exists at least one k-dominant character.InputThe first line contains string s consisting of lowercase Latin letters (1 ≤ |s| ≤ 100000).OutputPrint one number — the minimum value of k such that there exists at least one k-dominant character.12345678910111213ExamplesInputabacabaOutput2InputzzzzzOutput1InputabcdeOutput3题意:给你一个长度为n字符串,求最小的长度m,使得字符串中所有长度为m的子字符串中均包含某一种字符。123456789101112131415161718192021222324252627282930313233343536373839404142434445#include<bits/stdc++.h>using namespace std;#define ll long long#define pii pair<int,int>const int maxn=1000000+10;const int INF=0x3f3f3f3f;char s[maxn];int a[100],n;int vis[100];map<char,int>mp;bool check(int x){ memset(a,0,sizeof(a)); memset(vis,0,sizeof(vis)); for(int i=0;i<x;i++){ a[s[i]-'a']++; } for(int i=0;i<26;i++) if(!a[i]) vis[i]=1; for(int i=x;i<n;i++){ a[s[i]-'a']++; a[s[i-x]-'a']--; for(int j=0;j<26;j++) if(!a[j]) vis[j]=1; } for(int i=0;i<26;i++){ if(mp[i]){ if(!vis[i]) return true; } } return false;}int main(){ scanf("%s",s); n=strlen(s); int l=1,r=n; for(int i=0;i<n;i++){ mp[s[i]-'a']++; } while(l<=r){ int m=(l+r)/2; if(check(m)) r=m-1; else l=m+1; } printf("%d\n",r+1); return 0;}Maximum SubsequenceYou are given an array a consisting of n integers, and additionally an integer m. You have to choose some sequence of indices b1, b2, …, bk (1 ≤ b1 < b2 < … < bk ≤ n) in such a way that the value of is maximized. Chosen sequence can be empty.Print the maximum possible value of .InputThe first line contains two integers n and m (1 ≤ n ≤ 35, 1 ≤ m ≤ 109).The second line contains n integers a1, a2, …, an (1 ≤ ai ≤ 109).OutputPrint the maximum possible value of .123456789101112131415ExamplesInput4 45 2 4 1Output3Input3 20199 41 299Output19NoteIn the first example you can choose a sequence b = {1, 2}, so the sum is equal to 7 (and that's 3 after taking it modulo 4).In the second example you can choose a sequence b = {3}.题意:给你一个大小为n的数组和一个数m,求从数组中挑出任意多个数(可以为零,不可以重复),计算出的最大值,其中k为选出的数的个数。超大背包,将所有物品平均分成两部分,然后枚举所有状态。再枚举某一堆物品的所有值,二分从另一堆查找最优解即可。12345678910111213141516171819202122232425262728293031323334353637383940414243#include<bits/stdc++.h>using namespace std;#define ll long long#define pii pair<int,int>const int maxn=3000000+10;const int INF=0x3f3f3f3f;ll a[maxn];ll q[maxn],p[maxn];int main(){ ll n,m; scanf("%lld %lld",&n,&m); for(int i=0;i<n;i++){ scanf("%lld",&a[i]); a[i]%=m; } ll x=n/2; ll N=1<<x; for(int i=0;i<N;i++){ ll sum=0; for(int j=0;j<x;j++){ if((i>>j)&1) sum=(sum+a[j])%m; } p[i]=sum; } N=1<<(n-x); for(int i=0;i<N;i++){ ll sum=0; for(int j=0;j<n-x;j++){ if((i>>j)&1) sum=(sum+a[j+x])%m; } q[i]=sum; } sort(q,q+N); ll res=0; for(int i=0;i<1<<x;i++){ ll pos=lower_bound(q,q+N,m-1-p[i])-q; res=max(res,(p[i]+q[pos])%m); if(pos) res=max(res,(p[i]+q[pos-1])%m); } printf("%lld\n",res); return 0;}Alomost Identity PermutationsA permutation p of size n is an array such that every integer from 1 to n occurs exactly once in this array.Let’s call a permutation an almost identity permutation iff there exist at least n - k indices i (1 ≤ i ≤ n) such that pi = i.Your task is to count the number of almost identity permutations for given numbers n and k.InputThe first line contains two integers n and k (4 ≤ n ≤ 1000, 1 ≤ k ≤ 4).OutputPrint the number of almost identity permutations for given n and k.1234567891011121314151617Examplesinput4 1output1input4 2output7input5 3output31input5 4output76题意:问n个数的全排列中,有多少排列满足∑pi=i的值大于等于n−k。k≤4,枚举即可。对于k=1 , res=1;对于k=2 , res=C2n对于k=3 , res=C3n∗2对于k=4 , res=C4n∗9上面每一行的意义在于:从n个数中挑出k个数,每种选法又分别多少种方案使得∑ki=1pi=1 的值为0。code:123456789101112131415161718192021222324#include<bits/stdc++.h>using namespace std;#define ll long long#define pii pair<int,int>const int maxn=3000000+10;const int INF=0x3f3f3f3f;int main(){ ll n,k; scanf("%lld %lld",&n,&k); ll cur=n; ll res=1; ll fac=1; for(ll i=2;i<=k;i++){ fac=fac*i; cur=cur*(n-i+1)/i; if(i==2) res+=cur; if(i==3) res+=cur*2; if(i==4) res+=cur*9; } printf("%lld\n",res); return 0;}Alyona and SpreadsheetDuring the lesson small girl Alyona works with one famous spreadsheet computer program and learns how to edit tables.Now she has a table filled with integers. The table consists of n rows and m columns. By ai, j we will denote the integer located at the i-th row and the j-th column. We say that the table is sorted in non-decreasing order in the column j if ai, j ≤ ai + 1, j for all i from 1 to n - 1.Teacher gave Alyona k tasks. For each of the tasks two integers l and r are given and Alyona has to answer the following question: if one keeps the rows from l to r inclusive and deletes all others, will the table be sorted in non-decreasing order in at least one column? Formally, does there exist such j that ai, j ≤ ai + 1, j for all i from l to r - 1 inclusive.Alyona is too small to deal with this task and asks you to help!InputThe first line of the input contains two positive integers n and m (1 ≤ n·m ≤ 100 000) — the number of rows and the number of columns in the table respectively. Note that your are given a constraint that bound the product of these two integers, i.e. the number of elements in the table.Each of the following n lines contains m integers. The j-th integers in the i of these lines stands for ai, j (1 ≤ ai, j ≤ 109).The next line of the input contains an integer k (1 ≤ k ≤ 100 000) — the number of task that teacher gave to Alyona.The i-th of the next k lines contains two integers li and ri (1 ≤ li ≤ ri ≤ n).OutputPrint “Yes” to the i-th line of the output if the table consisting of rows from li to ri inclusive is sorted in non-decreasing order in at least one column. Otherwise, print “No”.123456789101112131415161718192021222324Exampleinput5 41 2 3 53 1 3 24 5 2 35 5 3 24 4 3 461 12 54 53 51 31 5outputYesNoYesYesYesNoNoteIn the sample, the whole table is not sorted in any column. However, rows 1–3 are sorted in column 1, while rows 4–5 are sorted in column 3.题意:从n∗m的矩阵中挑出从第l行到第r行,问在这(r−l+1)∗m的矩阵中是否存在某一列,使得这一列的元素按序号从小到大非递减。前缀和即可。计算每一行某个元素前面的所有的元素能够非递增的最小的起点,由于n,m的值未定,所以必须用一维数组来保存。在查找[l,r]行时,只需要看第r行的m个元素是否存在某个元素,他所在的非递减序列的起点小于等于l即可,由于不能用for循环查询,所以需要前缀和。1234567891011121314151617181920212223242526272829303132333435363738#include<bits/stdc++.h>using namespace std;#define ll long long#define pii pair<int,int>const int maxn=3000000+10;const int INF=0x3f3f3f3f;ll a[maxn];ll b[maxn];ll res[maxn];ll dp[maxn];int main(){ ll n,m,q,l,r; scanf("%lld %lld",&n,&m); for(int i=1;i<=n*m;i++){ scanf("%lld",&a[i]); } res[0]=1; for(int j=1;j<=m;j++){ ll pos=1; res[j]=1; for(int i=2;i<=n;i++){ if(a[m*(i-1)+j]>=a[(i-2)*m+j]) res[(i-1)*m+j]=pos;//非递减 else{//递减的话就是一个新的起点 res[m*(i-1)+j]=i; pos=i; } if(j>1) res[m*(i-1)+j]=min(res[m*(i-1)+j],res[m*(i-1)+j-1]);\\计算前缀最小值 } } scanf("%lld",&q); while(q--){ scanf("%lld %lld",&l,&r); if(res[r*m]<=l) printf("Yes\n"); else printf("No\n"); } return 0;}Shell GameBomboslav likes to look out of the window in his room and watch lads outside playing famous shell game. The game is played by two persons: operator and player. Operator takes three similar opaque shells and places a ball beneath one of them. Then he shuffles the shells by swapping some pairs and the player has to guess the current position of the ball.Bomboslav noticed that guys are not very inventive, so the operator always swaps the left shell with the middle one during odd moves (first, third, fifth, etc.) and always swaps the middle shell with the right one during even moves (second, fourth, etc.).Let’s number shells from 0 to 2 from left to right. Thus the left shell is assigned number 0, the middle shell is 1 and the right shell is 2. Bomboslav has missed the moment when the ball was placed beneath the shell, but he knows that exactly n movements were made by the operator and the ball was under shell x at the end. Now he wonders, what was the initial position of the ball?InputThe first line of the input contains an integer n (1 ≤ n ≤ 2·109) — the number of movements made by the operator.The second line contains a single integer x (0 ≤ x ≤ 2) — the index of the shell where the ball was found after n movements.OutputPrint one integer from 0 to 2 — the index of the shell where the ball was initially placed.123456789101112131415161718Examplesinput42output1input11output0NoteIn the first sample, the ball was initially placed beneath the middle shell and the operator completed four movements.During the first move operator swapped the left shell and the middle shell. The ball is now under the left shell.During the second move operator swapped the middle shell and the right one. The ball is still under the left shell.During the third move operator swapped the left shell and the middle shell again. The ball is again in the middle.Finally, the operators swapped the middle shell and the right shell. The ball is now beneath the right shell.题意:三个杯子,初始某个杯子中有一个小球,经过n次下列操作后,小球在第x号杯子(0,1,2号):此次操作次数的序号为第奇数次,交换0号和1号杯子。此次操作次数的序号为第偶数次,交换1号和2号杯子。问初始小球在那个杯子。模拟后发现,每6次操作一个循环,因此n mod 6后模拟计算即可。code:1234567891011121314151617181920212223#include<bits/stdc++.h>using namespace std;#define ll long long#define pii pair<int,int>const int maxn=3000000+10;const int INF=0x3f3f3f3f;int a[maxn];int res[maxn];int dp[maxn];int main(){ int n,m; scanf("%d %d",&n,&m); n%=6; int a[10]; a[0]=0;a[1]=1;a[2]=2; for(int i=1;i<=n;i++){ if(i&1) swap(a[0],a[1]); else swap(a[1],a[2]); } printf("%d\n",a[m]); return 0;}Hanoi FactoryOf course you have heard the famous task about Hanoi Towers, but did you know that there is a special factory producing the rings for this wonderful game? Once upon a time, the ruler of the ancient Egypt ordered the workers of Hanoi Factory to create as high tower as possible. They were not ready to serve such a strange order so they had to create this new tower using already produced rings.There are n rings in factory’s stock. The i-th ring has inner radius ai, outer radius bi and height hi. The goal is to select some subset of rings and arrange them such that the following conditions are satisfied:Outer radiuses form a non-increasing sequence, i.e. one can put the j-th ring on the i-th ring only if bj ≤ bi.Rings should not fall one into the the other. That means one can place ring j on the ring i only if bj > ai.The total height of all rings used should be maximum possible.InputThe first line of the input contains a single integer n (1 ≤ n ≤ 100 000) — the number of rings in factory’s stock.The i-th of the next n lines contains three integers ai, bi and hi (1 ≤ ai, bi, hi ≤ 109, bi > ai) — inner radius, outer radius and the height of the i-th ring respectively.OutputPrint one integer — the maximum height of the tower that can be obtained.1234567891011121314151617181920Examplesinput31 5 12 6 23 7 3output6input41 2 11 3 34 6 25 7 1output4NoteIn the first sample, the optimal solution is to take all the rings and put them on each other in order 3, 2, 1.In the second sample, one can put the ring 3 on the ring 4 and get the tower of height 3, or put the ring 1 on the ring 2 and get the tower of height 4.题意:给你n个圆环,每个圆环有一个外径和内径,现在将这些圆环堆起来,满足上面的圆环外径bi≤bj且bi>aj 其中aj,bj分别为下面一个圆环的内径和外径。问最高能将这些圆环堆多高。一个简单的模拟题。。。(我居然写了一下午的区间更新查询线段树)按照圆环外径从大到小排序,如果外径相同按照内径从大到小排序,然后按照顺序模拟即可,如果当前这个圆环放不到前面这个圆环,就继续往前面找,直到找到为止(这里可以用一个数组保存每个圆环找到的位置。code:123456789101112131415161718192021222324252627282930313233343536#include<bits/stdc++.h>using namespace std;#define ll long long#define pii pair<int,int>const int maxn=2000000+10;const int INF=0x3f3f3f3f;struct node{ ll l,r,h; bool friend operator<(node i,node j){ if(i.r==j.r) return i.l>j.l; return i.r>j.r; }}a[maxn];ll res[maxn];ll pre[maxn];int main(){ int n; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%lld %lld %lld",&a[i].l,&a[i].r,&a[i].h); } sort(a+1,a+n+1); res[1]=a[1].h; int cur=1; for(int i=2;i<=n;i++){ while(!(a[cur].l<a[i].r && a[i].r<=a[cur].r) && cur) cur=pre[cur]; res[i]=res[cur]+a[i].h; pre[i]=cur; cur=i; } ll ans=0; for(int i=1;i<=n;i++) ans=max(ans,res[i]); printf("%lld\n",ans); return 0;}Cloud of HashtagsVasya is an administrator of a public page of organization “Mouse and keyboard” and his everyday duty is to publish news from the world of competitive programming. For each news he also creates a list of hashtags to make searching for a particular topic more comfortable. For the purpose of this problem we define hashtag as a string consisting of lowercase English letters and exactly one symbol ‘#’ located at the beginning of the string. The length of the hashtag is defined as the number of symbols in it without the symbol ‘#’.The head administrator of the page told Vasya that hashtags should go in lexicographical order (take a look at the notes section for the definition).Vasya is lazy so he doesn’t want to actually change the order of hashtags in already published news. Instead, he decided to delete some suffixes (consecutive characters at the end of the string) of some of the hashtags. He is allowed to delete any number of characters, even the whole string except for the symbol ‘#’. Vasya wants to pick such a way to delete suffixes that the total number of deleted symbols is minimum possible. If there are several optimal solutions, he is fine with any of them.InputThe first line of the input contains a single integer n (1 ≤ n ≤ 500 000) — the number of hashtags being edited now.Each of the next n lines contains exactly one hashtag of positive length.It is guaranteed that the total length of all hashtags (i.e. the total length of the string except for characters ‘#’) won’t exceed 500 000.OutputPrint the resulting hashtags in any of the optimal solutions.12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849Examplesinput3#book#bigtown#bigoutput#b#big#biginput3#book#cool#coldoutput#book#co#coldinput4#car#cart#art#atoutput###art#atinput3#apple#apple#fruitoutput#apple#apple#fruitNoteWord a1, a2, ..., am of length m is lexicographically not greater than word b1, b2, ..., bk of length k, if one of two conditions hold:at first position i, such that ai ≠ bi, the character ai goes earlier in the alphabet than character bi, i.e. a has smaller character than b in the first position where they differ;if there is no such position i and m ≤ k, i.e. the first word is a prefix of the second or two words are equal.The sequence of words is said to be sorted in lexicographical order if each word (except the last one) is lexicographically not greater than the next word.For the words consisting of lowercase English letters the lexicographical order coincides with the alphabet word order in the dictionary.According to the above definition, if a hashtag consisting of one character '#' it is lexicographically not greater than any other valid hashtag. That's why in the third sample we can't keep first two hashtags unchanged and shorten the other two.题意:有n个新闻标题,你要删除最少的字符,使得最后所有的标题按照输入顺序字典序升序排列。并输出删除后的新闻标题。首先知道如果两个标题的字典序比较为降序,那么一定是要删除前面的那个标题,使得那个标题字典序变小。所以我们从后往前删除,能够保证每个标题删除的字符数量最少。code:12345678910111213141516171819202122232425262728293031323334#include<bits/stdc++.h>using namespace std;#define ll long long#define pii pair<int,int>const int maxn=3000000+10;const int INF=0x3f3f3f3f;string a[maxn];int len[maxn];int main(){ int n; cin >> n; for(int i=1;i<=n;i++){ cin >> a[i]; len[i]=a[i].length(); } for(int i=n-1;i>0;i--){ bool flag=0; for(int j=1;j<=min(len[i],len[i+1]);j++){ if(a[i][j]<a[i+1][j]) break; if(a[i][j]>a[i+1][j]){ a[i][j]='\0'; break; } } } for(int i=1;i<=n;i++){ for(int j=0;a[i][j]!='\0';j++){ cout << a[i][j]; } cout << endl; } return 0;}Game of Credit CardsAfter the fourth season Sherlock and Moriary have realized the whole foolishness of the battle between them and decided to continue their competitions in peaceful game of Credit Cards.Rules of this game are simple: each player bring his favourite n-digit credit card. Then both players name the digits written on their cards one by one. If two digits are not equal, then the player, whose digit is smaller gets a flick (knock in the forehead usually made with a forefinger) from the other player. For example, if n = 3, Sherlock’s card is 123 and Moriarty’s card has number 321, first Sherlock names 1 and Moriarty names 3 so Sherlock gets a flick. Then they both digit 2 so no one gets a flick. Finally, Sherlock names 3, while Moriarty names 1 and gets a flick.Of course, Sherlock will play honestly naming digits one by one in the order they are given, while Moriary, as a true villain, plans to cheat. He is going to name his digits in some other order (however, he is not going to change the overall number of occurences of each digit). For example, in case above Moriarty could name 1, 2, 3 and get no flicks at all, or he can name 2, 3 and 1 to give Sherlock two flicks.Your goal is to find out the minimum possible number of flicks Moriarty will get (no one likes flicks) and the maximum possible number of flicks Sherlock can get from Moriarty. Note, that these two goals are different and the optimal result may be obtained by using different strategies.InputThe first line of the input contains a single integer n (1 ≤ n ≤ 1000) — the number of digits in the cards Sherlock and Moriarty are going to use.The second line contains n digits — Sherlock’s credit card number.The third line contains n digits — Moriarty’s credit card number.OutputFirst print the minimum possible number of flicks Moriarty will get. Then print the maximum possible number of flicks that Sherlock can get from Moriarty.1234567891011121314151617Examplesinput3123321output02input28800output20NoteFirst sample is elaborated in the problem statement. In the second sample, there is no way Moriarty can avoid getting two flicks.题意:S 某,M某分别有一张序号长度为n的信用卡,他们定了一个规则:比赛分为n局,每局S某,M某从n个数字中分别不重复的取出一个数字,谁的数字小谁得一分,平局不算分。问如果随机排列这些数字,S某可能的最高得分和M某可能的最低得分分别为多少。模拟题,算最高分时只要从小到大让S某牌去压M某小于自己当前牌大小的牌即可。算最低分时,只要从大到小让M某去压S某大于等于自己当前牌大小的牌即可。code:123456789101112131415161718192021222324252627282930313233#include<bits/stdc++.h>using namespace std;#define ll long long#define pii pair<int,int>const int maxn=1000000+10;const int INF=0x3f3f3f3f;char s[maxn],t[maxn];int a[100],b[100];int main(){ int n; scanf("%d",&n); scanf("%s %s",s,t); for(int i=0;i<n;i++){ a[s[i]-'0']++; b[t[i]-'0']++; } int res1=0,res2=0; int sum=0; for(int i=0;i<10;i++){ sum+=a[i]; res1+=min(b[i],sum); sum-=min(b[i],sum); } sum=0; for(int i=9;i>=0;i--){ res2+=min(a[i],sum); sum-=min(a[i],sum); sum+=b[i]; } printf("%d\n%d\n",n-res1,res2); return 0;}]]></content>
<categories>
<category>ACM</category>
<category>review</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>review</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Rday5]]></title>
<url>%2F2019%2F09%2F21%2FRday5%2F</url>
<content type="text"><![CDATA[Rday5练习2048 GameYou are playing a variation of game 2048. Initially you have a multiset s of n integers. Every integer in this multiset is a power of two.You may perform any number (possibly, zero) operations with this multiset.During each operation you choose two equal integers from s, remove them from s and insert the number equal to their sum into s.For example, if s={1,2,1,1,4,2,2} and you choose integers 2 and 2, then the multiset becomes {1,1,1,4,4,2}.You win if the number 2048 belongs to your multiset. For example, if s={1024,512,512,4} you can win as follows: choose 512 and 512, your multiset turns into {1024,1024,4}. Then choose 1024 and 1024, your multiset turns into {2048,4} and you win.You have to determine if you can win this game.You have to answer q independent queries.InputThe first line contains one integer q (1≤q≤100) – the number of queries.The first line of each query contains one integer n (1≤n≤100) — the number of elements in multiset.The second line of each query contains n integers s1,s2,…,sn (1≤si≤229) — the description of the multiset. It is guaranteed that all elements of the multiset are powers of two.OutputFor each query print YES if it is possible to obtain the number 2048 in your multiset, and NO otherwise.You may print every letter in any case you want (so, for example, the strings yEs, yes, Yes and YES will all be recognized as positive answer).123456789101112131415161718192021222324252627ExampleInput641024 512 64 51212048364 512 224096 472048 2 2048 2048 2048 2048 204822048 4096OutputYESYESNONOYESYESNoteIn the first query you can win as follows: choose 512 and 512, and s turns into {1024,64,1024}. Then choose 1024 and 1024, and s turns into {2048,64} and you win.In the second query s contains 2048 initially.题意根据所给的数字集合,判断里面的数字相加是否是2048就可以了可以先排一下序,因为都是2的幂数,所以可以放心的直接相加就行了code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748#include<iostream>#include<cstring>#include<algorithm>#include<cmath>using namespace std;typedef long long ll;const int mod = 1e9 + 7;const int INF = 0x3f3f3f3f;const int maxx = 1e5;bool cmp(int x, int y){ return x > y;}int a[maxx];int main(){ int t; int n; cin >> t; while(t --) { cin >> n; int x; int flag = 0, sum = 0; for(int i = 0; i < n; i ++) cin >> a[i]; sort(a, a + n, cmp); for(int i = 0; i < n; i ++) { if(a[i] > 2048) continue; else { sum += a[i]; } if(sum == 2048 || a[i] == 2048) { flag = 1; break; } } if(flag == 1) puts("YES"); else puts("NO"); } return 0;}Perfect TeamYou may have already known that a standard ICPC team consists of exactly three members. The perfect team however has more restrictions. A student can have some specialization: coder or mathematician. She/he can have no specialization, but can’t have both at the same time.So the team is considered perfect if it includes at least one coder, at least one mathematician and it consists of exactly three members.You are a coach at a very large university and you know that c of your students are coders, m are mathematicians and x have no specialization.What is the maximum number of full perfect teams you can distribute them into?Note that some students can be left without a team and each student can be a part of no more than one team.You are also asked to answer q independent queries.InputThe first line contains a single integer q (1≤q≤104) — the number of queries.Each of the next q lines contains three integers c, m and x (0≤c,m,x≤108) — the number of coders, mathematicians and students without any specialization in the university, respectively.Note that the no student is both coder and mathematician at the same time.OutputPrint q integers — the i-th of them should be the answer to the i query in the order they are given in the input. The answer is the maximum number of full perfect teams you can distribute your students into.12345678910111213141516171819202122232425ExampleInput61 1 13 6 00 0 00 1 110 1 104 4 1Output130013NoteIn the first example here are how teams are formed:the only team of 1 coder, 1 mathematician and 1 without specialization;all three teams consist of 1 coder and 2 mathematicians;no teams can be formed;no teams can be formed;one team consists of 1 coder, 1 mathematician and 1 without specialization, the rest aren't able to form any team;one team consists of 1 coder, 1 mathematician and 1 without specialization, one consists of 2 coders and 1 mathematician and one consists of 1 coder and 2 mathematicians.题解:这道题重点是判断一下数学家和编译员的人数,如果为0,是肯定组不成的不为0的话,要判断数学家和编译员的人数之中最小的值和最小能够组成完美队伍的值之间,取最小值code:12345678910111213141516171819202122232425262728293031#include<iostream>#include<cstring>#include<algorithm>#include<cmath>using namespace std;typedef long long ll;const int mod = 1e9 + 7;const int INF = 0x3f3f3f3f;const int maxx = 1e5;int main(){ int c, m, x;//c是程序员,m是数学家,x是无专业人 int t; cin >> t; while(t --) { cin >> c >> m >> x; int ans = 0; if(c == 0 || m == 0) { puts("0"); continue; } int minx = min(c, m); int len = (c + m + x) / 3; ans = min(minx, len); cout << ans << '\n'; } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>review</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>review</tag>
<tag>暴力</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Rday4]]></title>
<url>%2F2019%2F09%2F20%2FRday4%2F</url>
<content type="text"><![CDATA[Rday4DFSOil Deposits应该可以算是入门题吧The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSurvComp works with one large rectangular region of land at a time, and creates a grid that divides the land into numerous square plots. It then analyzes each plot separately, using sensing equipment to determine whether or not the plot contains oil. A plot containing oil is called a pocket. If two pockets are adjacent, then they are part of the same oil deposit. Oil deposits can be quite large and may contain numerous pockets. Your job is to determine how many different oil deposits are contained in a grid.InputThe input file contains one or more grids. Each grid begins with a line containing m and n, the number of rows and columns in the grid, separated by a single space. If m = 0 it signals the end of the input; otherwise 1 <= m <= 100 and 1 <= n <= 100. Following this are m lines of n characters each (not counting the end-of-line characters). Each character corresponds to one plot, and is either *', representing the absence of oil, or@’, representing an oil pocket.OutputFor each grid, output the number of distinct oil deposits. Two different pockets are part of the same oil deposit if they are adjacent horizontally, vertically, or diagonally. An oil deposit will not contain more than 100 pockets.123456789101112131415161718192021Sample Input1 1*3 5*@*@***@***@*@*1 8@@****@*5 5****@*@@*@*@**@@@@*@@@**@0 0Sample Output0122题解:存图,套用一下DFS大概模板就行了code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768#include<bits/stdc++.h>using namespace std;const int mod = 101;char a[mod][mod];int vis[mod][mod];int ans;int n, m;int d[8][2] = { -1, 1, -1, 0, -1, -1, 0, 1, 0, -1, 1, 1, 1, 0, 1, -1};void DFS(int x, int y){ if(x < 0 || y < 0 || x >=n || y >= m) return ; int xx, yy;// vis[x][y] = 1; for(int i = 0; i < 8; i ++) { xx = x + d[i][0]; yy = y + d[i][1]; if(xx >= 0 && yy >= 0 && xx < n && yy < m && a[xx][yy] != '*') { a[xx][yy] = '*'; DFS(xx, yy); } }}int main(){ int sx, sy; while(~scanf("%d %d",&n, &m) && n) {// memset(vis, 0, sizeof(vis)); ans = 0; for(int i = 0; i < n; i ++) { for(int j = 0; j < m; j ++) { cin >> a[i][j]; } } for(int i = 0; i < n; i ++) { for(int j = 0; j < m; j ++) { if(a[i][j] == '@') { ans ++; DFS(i, j); } } } cout << ans << endl; } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>review</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>review</tag>
<tag>DFS</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Rday3]]></title>
<url>%2F2019%2F09%2F19%2FRday3%2F</url>
<content type="text"><![CDATA[Rday3贪心排队接水题目描述有n个人在一个水龙头前排队接水,假如每个人接水的时间为Ti,请编程找出这n个人排队的一种顺序,使得n个人的平均等待时间最小。输入格式输入文件共两行,第一行为n;第二行分别表示第1个人到第n个人每人的接水时间T1,T2,…,Tn,每个数据之间有1个空格。输出格式输出文件有两行,第一行为一种排队顺序,即1到n的一种排列;第二行为这种排列方案下的平均等待时间(输出结果精确到小数点后两位)。123456789101112输入输出样例输入1056 12 1 99 1000 234 33 55 99 812输出3 2 7 8 1 4 9 6 10 5291.90说明/提示n<=1000ti<=1e6,不保证ti不重复当ti重复时,按照输入顺序即可(sort是可以的)题意:求最短的节水时间,看完题意分析可知,这题就是说单个人节水快的人先接水,这样后面人等的时间也就比较短了,这样最后平均下来的时间也会比较短我见好多解法都是结构体解的,下面的解法利用一个巧妙地思维解,没有运用到结构体因为数据是在1000之内的,所以可以乘上个1001,这样后面排序的时候序号不干扰排序后面的结果%1001是序号,/1001是时间code:123456789101112131415161718192021222324252627282930313233343536#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<map>using namespace std;typedef long long ll;const int mod = 1e9 + 7;const int INF = 0x3f3f3f3f;const int maxx = 1e5;int a[maxx];int main(){ int t, x; cin >> t; double sum = 0; for(int i = 1; i <= t; i ++) { cin >> x; //接水人所用的时间 a[i] = x * 1001 + i; } sort(a + 1, a + t + 1); for(int i = 1; i <= t; i ++) { printf("%d ",a[i] % 1001); //表示其他人需要等的时间 sum += a[i] / 1001 * (t - i); } puts(""); double ans = sum / t; printf("%.2lf\n",ans); return 0;}]]></content>
<categories>
<category>ACM</category>
<category>review</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>review</tag>
<tag>贪心</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Rday2]]></title>
<url>%2F2019%2F09%2F18%2FRday2%2F</url>
<content type="text"><![CDATA[Rday2二分Strange fuctionNow, here is a fuction:F(x) = 6 x^7+8x^6+7x^3+5x^2-y*x (0 <= x <=100)Can you find the minimum value when x is between 0 and 100.InputThe first line of the input contains an integer T(1<=T<=100) which means the number of test cases. Then T lines follow, each line has only one real numbers Y.(0 < Y <1e10)OutputJust the minimum value (accurate up to 4 decimal places),when x is between 0 and 100.1234567Sample Input2100200Sample Output-74.4291-178.8534题解:1234这道题就是一个数学思维题相当于y是个常数求 F(x) = 6 * x^7+8*x^6+7*x^3+5*x^2-y*x (0 <= x <=100)这个函数的最小值,令F' = 0,得出x,y的方程,用二分法解方程得x0(易证得x0>=0 && x0<=100),则F'(x0) = 0,由F'' 在[0-100]上恒大于0,所以F'在[0-100]上单增,所以F'(x)<0(x<x0),F'(x)>0(x>x0),所以F(x)在x=x0处取得最小值,所以本题主要就是二分求解方程的x0,然后直接带入x0,y计算即可。code:123456789101112131415161718192021222324252627282930313233343536373839#include<bits/stdc++.h>using namespace std;const double mod = 1e-6;double qiu_y(double x){ return 42 * pow(x, 6.0) + 48 * pow(x, 5.0) + 21 * pow(x, 2.0) + 10 * x;}double f(double x, double y){ return 6 * pow(x, 7) + 8 * pow(x, 6) + 7 * pow(x, 3) + 5 * pow(x, 2) - x * y;}int main(){ int t; double l, r, mid, y, res; cin >> t; while(t --) { cin >> y; l = 0.0, r = 100.0; while(r - l > mod) { mid = (r + l) / 2; res = qiu_y(mid); if(res < y) { l = mid + 1e-8; } else { r = mid - 1e-8; } } printf("%0.4lf\n",f(mid, y)); } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>review</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>review</tag>
<tag>二分</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Rday1]]></title>
<url>%2F2019%2F09%2F17%2FRday1.0%2F</url>
<content type="text"><![CDATA[Rday1树的直径Roads in the NorthBuilding and maintaining roads among communities in the far North is an expensive business. With this in mind, the roads are build such that there is only one route from a village to a village that does not pass through some other village twice.Given is an area in the far North comprising a number of villages and roads among them such that any village can be reached by road from any other village. Your job is to find the road distance between the two most remote villages in the area.The area has up to 10,000 villages connected by road segments. The villages are numbered from 1.InputInput to the problem is a sequence of lines, each containing three positive integers: the number of a village, the number of a different village, and the length of the road segment connecting the villages in kilometers. All road segments are two-way.OutputYou are to output a single integer: the road distance between the two most remote villages in the area.12345678Sample Input5 1 61 4 56 3 92 6 86 1 7Sample Output22题解:首先分析题意,表示的是一个村落到另一个村落的距离并且带有权值,自然可以想到并查集或者树的直径,再加上所求的是最远的两个村落之间的最大的费用,可以知道,这道题就是求树的直径树的直径做法:跑两边BFS就可以了,其中BFS表示找到一端的端点整体做法:先vector存图,然后用队列和pair来写BFS,这个和模板有点相识,运用相关思想可解code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364#include<iostream>#include<stdio.h>#include<cstring>#include<algorithm>#include<cmath>#include<vector>#include<queue>using namespace std;typedef long long ll;const int mod = 1e9 + 7;const int INF = 0x3f3f3f3f;const int maxx = 1e5;bool vis[maxx];int dis[maxx];int en;int ans;vector<pair<int, int> >v[maxx];int bfs(int x){ queue<int> q; memset(vis, 0, sizeof vis); memset(dis, 0, sizeof dis); vis[x] = 1; q.push(x); en = 0; ans = 0; while(!q.empty()) { int f = q.front(); q.pop(); if(dis[f] > ans) { ans = dis[f]; en = f; } pair<int, int> t; for(int i = 0; i < v[f].size(); i ++) { t = v[f][i]; if(vis[t.first] == 0) { vis[t.first] = 1; dis[t.first] = t.second + dis[f]; q.push(t.first); } } } return en;}int main(){ int n, m, k; for(int i = 0; i < v[i].size(); i ++) v[i].clear(); while(scanf("%d %d %d",&n, &m, &k)!=EOF) { v[n].push_back(make_pair(m, k)); v[m].push_back(make_pair(n, k)); } bfs(1); bfs(en); printf("%d\n",ans); return 0;}]]></content>
<categories>
<category>ACM</category>
<category>review</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>review</tag>
<tag>树的直径</tag>
</tags>
</entry>
<entry>
<title><![CDATA[css基础]]></title>
<url>%2F2019%2F09%2F13%2Fcss%2F</url>
<content type="text"><![CDATA[css基础时隔这么久了,更新一下css的内容,哈哈css简介众所周知,网页设计是由html+css+js组成的今天就了解一下css吧,也就是”网页化妆师”细致链接csscss选择器1231.CSS 的选择器是 CSS最基础也是最重要的一个知识点。2.选择器的权重:谁的权力大,就听谁的,同理,选择器权重也是一样,谁的权重值高,应用谁的3.用途:用于准确的选中元素,并赋予样式选择器分类类(class)选择器:通过标签的 class 属性 ,选择对应的元素 借助了一个类的概念,一处定义,可以多处使用id选择器:通过标签的 id 属性,选择 对应的元素 注意:id选择器唯一群组选择器:群组选择器是可以同时选择多个标签的选择器层次选择器:层次选择器分为,子代、后代、相邻和兄弟等四种选择器1234567子代选择器:> eg:.div>ul后代选择器:一个空格 eg:.div ul相邻选择器:只能选择与当前选择的标签的下一个,不包括上一个,用+表示 eg:.top+.contont兄弟选择器:只能选择当前选择器的下面的同一层次的选择器,不包括前面的,用~表示 eg:.top~contont属性选择器:一般用于自定义 eg:有一个<div class="box"></div> 使用的时候为 .div[class="box"]分组选择器:用,隔开就行了伪类选择器:首先是link,其次是hover,然后是visited,然后是actived选择器优先级123Id选择器 > class 选择器 > 元素选择器Id选择器:100 > class 选择器:10 > 元素选择器:1伪类选择器:1234567- link:未访问过的样式- visited:访问过后的样式- hover:划过的样式- active:激活的样式用法12345678910111213141516171819202122232425262728<head> <style> .box{ height: 400px; width:400px; background: red; } .box:hover{ background: skyblue; } a{ text-decoration:none; } a:link{ color: red; } a:visited{ color: yellow; } a:active{ color: green; } </style></head><body> <div class="box"></div> <a>lalla</a></body>CSS字体/文本123456字体font-family字体大小font-size字体样式font-style字体粗细font-weight字体大小写font-variant复合样式font文本常用样式:123456对齐方式text-align首行缩进text-indent文本线text-decoration字距letter-spacing词距word-spacing行高line-height]]></content>
<categories>
<category>html</category>
<category>css</category>
</categories>
<tags>
<tag>学习</tag>
<tag>css</tag>
<tag>html</tag>
</tags>
</entry>
<entry>
<title><![CDATA[集训中学到的方法]]></title>
<url>%2F2019%2F08%2F30%2F%E9%9B%86%E8%AE%AD%E4%B8%AD%E5%AD%A6%E5%88%B0%E7%9A%84%E6%96%B9%E6%B3%95%2F</url>
<content type="text"><![CDATA[学习就该如贪心!!一直向前~!记录一些会用到并且好用的函数或者是容易混淆的知识点持续更新有关acm中精度的问题:https://www.cnblogs.com/crazyacking/p/4668471.htmlSTL的定义方式:set/stack/queue/vector <int/string> 定义名称;set有自动排序的功能(从小到大)set里面用的是平衡二叉搜索树(也就是红黑树)维护string 字符串名称;map<string/int, int/string> 名称;set的迭代器:set:: iterator it;这个it是为指针用法eg:it = st.begin();cout << it;it ++;for(; it != st.end(); it ++){cout << “ “ << it;}map的迭代器:map<string, int> :: iterator mp;这个mp用法要用mp -> first 或者mp -> second 来表示eg:map<string, int> :: iterator it1;map<string, node> :: iterator it2;for(it2 = mp.begin(); it2 != mp.end(); it2 ++){cout << it2 -> first << endl;for(it1 = mp[it2 -> first].count.begin(); it1 != mp[it2 -> first].count.end(); it1 ++){cout << “|—-“ << it1 -> first << “(“ << it1 -> second << “)” << endl;}}嵌套map用法可以为struct node{map<string, int> count;};map<string, node> mp;用的时候为:mp[string].count[string] ++;或者一些操作二分查找–binary_search的用法头文件 #include <algorithm>使用方法:123456a.函数模板:binary_search(arr[],arr[]+size , indx)b.参数说明: arr[]: 数组首地址 size:数组元素个数 indx:需要查找的值c.函数功能: 在数组中以二分法检索的方式查找,若在数组(要求数组元素非递减)中查找到indx元素则真,若查找不到则返回值为假。lower_bound查找第一个大于或等于某个元素的位置使用方法:12345678910111213a.函数模板:lower_bound(arr[],arr[]+size , indx):b.参数说明: arr[]: 数组首地址 size:数组元素个数 indx:需要查找的值c.函数功能:函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置(注意是地址)。如果所有元素都小于val,则返回last的位置d.举例如下: 一个数组number序列为:4,10,11,30,69,70,96,100.设要插入数字3,9,111.pos为要插入的位置的下标,则 /*注意因为返回值是一个指针,所以减去数组的指针就是int变量了*/ pos = lower_bound( number, number + 8, 3) - number,pos = 0.即number数组的下标为0的位置。 pos = lower_bound( number, number + 8, 9) - number, pos = 1,即number数组的下标为1的位置(即10所在的位置)。 pos = lower_bound( number, number + 8, 111) - number, pos = 8,即number数组的下标为8的位置(但下标上限为7,所以返回最后一个元素的下一个元素)。e.注意:函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置,且last的位置是越界的!upper_bound: 查找第一个大于某个位置的元素的位置使用方法:12345678a.函数模板:upper_bound(arr[],arr[]+size , indx):b.参数说明: arr[]: 数组首地址 size:数组元素个数 indx:需要查找的值c.函数功能:函数upper_bound()返回的在前闭后开区间查找的关键字的上界,返回大于val的第一个元素位置 例如:一个数组number序列1,2,2,4.upper_bound(2)后,返回的位置是3(下标)也就是4所在的位置,同样,如果插入元素大于数组中全部元素,返回的是last。(注意:数组下标越界) 返回查找元素的最后一个可安插位置,也就是“元素值>查找值”的第一个元素的位置 。unique函数类属性算法unique的作用是从输入序列中“删除”所有相邻的重复元素。该算法删除相邻的重复元素,然后重新排列输入范围内的元素,并且返回一个迭代器(容器的长度没变,只是元素顺序改变了),表示无重复的值范围得结束。1234// sort words alphabetically so we can find the duplicatessort(words.begin(), words.end()); vector<string>::iterator end_unique = unique(words.begin(), words.end()); words.erase(end_unique, words.end());在STL中unique函数是一个去重函数, unique的功能是去除相邻的重复元素(只保留一个),其实它并不真正把重复的元素删除,是把重复的元素移到后面去了,然后依然保存到了原数组中,然后 返回去重后最后一个元素的地址,因为unique去除的是相邻的重复元素,所以一般用之前都会要排一下序。若调用sort后,vector的对象的元素按次序排列如下:sort jumps over quick red red slow the the turtle注意,words的大小并没有改变,依然保存着10个元素;只是这些元素的顺序改变了。调用unique“删除”了相邻的重复值。给“删除”加上引号是因为unique实际上并没有删除任何元素,而是将无重复的元素复制到序列的前段,从而覆盖相邻的重复元素。unique返回的迭代器指向超出无重复的元素范围末端的下一个位置。注意:算法不直接修改容器的大小。如果需要添加或删除元素,则必须使用容器操作。Eg:123456789101112131415161718192021222324252627#include <iostream>#include <cassert>#include <algorithm>#include <vector>#include <string>#include <iterator> using namespace std; int main(){ //cout<<"Illustrating the generic unique algorithm."<<endl; const int N=11; int array1[N]={1,2,0,3,3,0,7,7,7,0,8}; vector<int> vector1; for (int i=0;i<N;++i) vector1.push_back(array1[i]); vector<int>::iterator new_end; new_end=unique(vector1.begin(),vector1.end()); //"删除"相邻的重复元素 assert(vector1.size()==N); vector1.erase(new_end,vector1.end()); //删除(真正的删除)重复的元素 copy(vector1.begin(),vector1.end(),ostream_iterator<int>(cout," ")); cout<<endl; return 0;}gcd的前缀后缀维护说到gcd,就不得不提一下C++11中子代有内置gcd函数,用法是 __gcd(a, b);题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6025持续更新PS:暂时不会讲解,先看代码吧,等以后理解透了在讲解code:12345678910111213141516171819202122232425262728293031323334353637383940#include<iostream>#include<cmath>#include<cstring>using namespace std;int gcd(int a,int b){ if(a<b){ int t=a; a=b;b=t; } return b==0?a:gcd(b,a%b);}int a[1000005],q[1000005],h[1000005];int main(){ int t; cin>>t; while(t--){ int n; cin>>n; memset(q,0,sizeof(q)); memset(h,0,sizeof(h)); int i; for(i=0;i<n;i++){ cin>>a[i]; } q[0]=a[0]; for(i=1;i<n-1;i++){ q[i]=gcd(q[i-1],a[i]); } h[n-1]=a[n-1]; for(i=n-2;i>0;i--){ h[i]=gcd(h[i+1],a[i]); } int ans=max(q[n-2],h[1]); for(i=1;i<n-1;i++){ ans=max(ans,gcd(q[i-1],h[i+1])); } cout<<ans<<endl; } return 0;}C++中auto的用法C++98 auto早在C++98标准中就存在了auto关键字,那时的auto用于声明变量为自动变量,自动变量意为拥有自动的生命期,这是多余的,因为就算不使用auto声明,变量依旧拥有自动的生命期:123int a =10 ; //拥有自动生命期auto int b = 20 ;//拥有自动生命期static int c = 30 ;//延长了生命期C++98中的auto多余且极少使用,C++11已经删除了这一用法,取而代之的是全新的auto:变量的自动类型推断。C++11 autoauto可以在声明变量的时候根据变量初始值的类型自动为此变量选择匹配的类型,类似的关键字还有decltype。举个例子:123int a = 10;auto au_a = a;//自动类型推断,au_a为int类型cout << typeid(au_a).name() << endl;typeid运算符可以输出变量的类型。程序的运行结果输出了int这种用法就类似于C#中的var关键字。auto的自动类型推断发生在编译期,所以使用auto并不会造成程序运行时效率的降低。而是否会造成编译期的时间消耗,我认为是不会的,在未使用auto时,编译器也需要得知右操作数的类型,再与左操作数的类型进行比较,检查是否可以发生相应的转化,是否需要进行隐式类型转换。为什么用auto:用于代替冗长复杂、变量使用范围专一的变量声明。想象一下在没有auto的时候,我们操作标准库时经常需要这样:1234567891011#include<string>#include<vector>using namespace std;int main(){ vector<string> vs; for (vector<string>::iterator i = vs.begin(); i != vs.end(); i++) { //... }}使用auto 可以简化代码:12345678910#include<string>#include<vector>int main(){ vector<string> vs; for (auto i = vs.begin(); i != vs.end(); i++) { //.. }}pair的用法pair的应用pair是将2个数据组合成一组数据,当需要这样的需求时就可以使用pair,如stl中的map就是将key和value放在一起来保存。另一个应用是,当一个函数需要返回2个数据的时候,可以选择pair。 pair的实现是一个结构体,主要的两个成员变量是first second 因为是使用struct不是class,所以可以直接使用pair的成员变量。1234567pair<T1, T2> p1; //创建一个空的pair对象(使用默认构造),它的两个元素分别是T1和T2类型,采用值初始化。pair<T1, T2> p1(v1, v2); //创建一个pair对象,它的两个元素分别是T1和T2类型,其中first成员初始化为v1,second成员初始化为v2。make_pair(v1, v2); // 以v1和v2的值创建一个新的pair对象,其元素类型分别是v1和v2的类型。p1 < p2; // 两个pair对象间的小于运算,其定义遵循字典次序:如 p1.first < p2.first 或者 !(p2.first < p1.first) && (p1.second < p2.second) 则返回true。p1 == p2; // 如果两个对象的first和second依次相等,则这两个对象相等;该运算使用元素的==操作符。p1.first; // 返回对象p1中名为first的公有数据成员p1.second; // 返回对象p1中名为second的公有数据成员pair的创建和初始化1234567891011pair包含两个数值,与容器一样,pair也是一种模板类型。但是又与之前介绍的容器不同;在创建pair对象时,必须提供两个类型名,两个对应的类型名的类型不必相同pair<string, string> anon; // 创建一个空对象anon,两个元素类型都是stringpair<string, int> word_count; // 创建一个空对象 word_count, 两个元素类型分别是string和int类型pair<string, vector<int> > line; // 创建一个空对象line,两个元素类型分别是string和vector类型当然也可以在定义时进行成员初始化:pair<string, string> author("James","Joy"); // 创建一个author对象,两个元素类型分别为string类型,并默认初始值为James和Joy。pair<string, int> name_age("Tom", "18");pair<string, int> name_age2(name_age); // 拷贝构造初始化12345678pair类型的使用相当的繁琐,如果定义多个相同的pair类型对象,可以使用typedef简化声明:typedef pair<string,string> Author;Author proust("March","Proust");Author Joy("James","Joy");变量间赋值:pair<int, double> p1(1, 1.2);pair<int, double> p2 = p1; //operator =pair对象的操作1234567891011pair<int ,double> p1;p1.first = 1;p1.second = 2.5;cout<<p1.first<<' '<<p1.second<<endl;//输出结果:1 2.5string firstBook;if(author.first=="James" && author.second=="Joy") firstBook="Stephen Hero";生成新的pair对象还可以利用make_pair创建新的pair对象:12345678910111213141516pair<int, double> p1;p1 = make_pair(1, 1.2);cout << p1.first << p1.second << endl;//output: 1 1.2int a = 8;string m = "James";pair<int, string> newone;newone = make_pair(a, m);cout << newone.first << newone.second << endl;//output: 8 James通过tie获取pair元素值在某些清况函数会以pair对象作为返回值时,可以直接通过std::tie进行接收。比如:1234567891011121314std::pair<std::string, int> getPreson() { return std::make_pair("Sven", 25);}int main(int argc, char **argv) { std::string name; int ages; std::tie(name, ages) = getPreson(); std::cout << "name: " << name << ", ages: " << ages << std::endl; return 0;}有关字符串的一些用法1.isalpha(c) ~判断是否为英文字符2.tolower(c) ~将字符转换成小写3.字符串输入sstream4.将字符串分割成单词:stringstream temp(str); //分割成一个个单词5.将字符串插入进set中,自动排序~string的用法提到字符串就必须提一句string,这个是真的好用!!!!简洁明了string 的用法和 int 基本上没啥差别,也就是定义的类型不同,string功能多一点罢了(string毕竟是字符串嘛)定义:12345string str;string str[100];str = "aaa";//直接赋值for(int i = 1; i <= n; i ++) cin >> str[i];//输入赋值比较说起来比较就更令人发指了!!!不知道比起来某个char方便多少呢。1234str1 = "abc";str2 = "abb";if(str1 > str2) puts("1");//输出结果 1没错,你没看错!!就是直接比较大小。。持续更新string 功能stringstream的用法:stringstream是 C++ 提供的另一个字串型的串流(stream)物件,和之前学过的iostream、fstream有类似的操作方式。要使用stringstream, 必须先加入这一行:#includestringstream主要是用在將一个字符串分割,可以先用.clear( )以及.str( )將指定字串设定成一开始的內容,再用>>把个別的资料输出。Eg:題目:输入的第一行有一个数字 N 代表接下來有 N 行资料,每一行资料里有不固定个数的整数(最多20个,每行最大200个字元),编程將每行的总和打印出來。输入:31 2 320 17 23 54 77 60111 222 333 444 555 666 777 888 999输出:625149951234567891011121314151617181920212223242526272829#include <iostream>#include <string>#include <sstream>using namespace std;int main(){ string s; stringstream ss; int n; cin >> n; getline(cin, s); //读取换行 for (int i = 0; i < n; i++) { getline(cin, s); ss.clear(); ss.str(s); int sum = 0; while (1) { int a; ss >> a; if(ss.fail()) break; sum += a; } cout << sum << endl; } return 0;}使用stringstream简化类型转换C++标准库中的提供了比ANSI C的<stdio.h>更高级的一些功能,即单纯性、类型安全和可扩展性。接下来,我将举例说明怎样使用这些库来实现安全和自动的类型转换。Eg:12345678910111213141516171819#include <stdio.h>int main(){ int n = 10000; char s[10]; sprintf(s, "%d", n); //s中的内容为“10000” //到目前为止看起来还不错。但是,对上面代码的一个微小的改变就会使程序发生错误 printf("%s\n", s); sprintf(s, "%f", n); //错误的格式化符 printf("%s\n", s); return 0;}详细学习链接:http://blog.csdn.net/zhang_xueping/article/details/47846807http://blog.csdn.net/u014097230/article/details/52089530优先队列—自动排序!!!说道优先队列就必须提一句优先队列别有back()操作,并且第一个元素不是用front()而是top(),,,front()是队列的优先队列是一种特殊的队列,在学习堆排序的时候就有所了解。堆排序奇偶剪枝点这里]]></content>
<categories>
<category>ACM</category>
<category>Algorithm</category>
</categories>
<tags>
<tag>学习</tag>
<tag>C++</tag>
<tag>ACM</tag>
<tag>Algorithm</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Linux常用命令]]></title>
<url>%2F2019%2F08%2F26%2FLinux%E5%91%BD%E4%BB%A4%2F</url>
<content type="text"><![CDATA[Linux的一些常用命令整理也方便自己以后查询详情链接ls就是 list 的缩写,通过 ls 命令不仅可以查看 linux 文件夹包含的文件,而且可以查看文件权限(包括目录、文件夹、文件权限)查看目录信息等等。mkdir用于新建一个新目录pwd显示当前工作目录cd切换文件路径,cd将给定的文件夹(或者目录)设置成当前工作目录eg:cd desktoprmdir删除给定目录eg:mkdir testrmdir testrm删除给定的文件cp对文件进行复制mv对文件或者文件夹进行移动,如果文件或者文件夹存在于当前工作目录,还可以对文件或者文件夹重新命名cat用于标准输出(监控器或者屏幕)上查看文件内容tail默认在标准输出上显示给定文件的最后10行内容,可以使用tail -n N 指定在标准输出上显示文件的最后N行内容。less按页或按窗口打印文件内容。在查看包含大量文本数据的大文件时是非常有用和高效的。你可以使用Ctrl+F向前翻页,Ctrl+B向后翻页。grep在给定的文件中搜寻指定的字符串。grep -i “” 在搜寻时会忽略字符串的大小写,而grep -r “” 则会在当前工作目录的文件中递归搜寻指定的字符串。find这个命令会在给定位置搜寻与条件匹配的文件。你可以使用find -name 的-name选项来进行区分大小写的搜寻,find -iname 来进行不区分大小写的搜寻。tar命令能创建、查看和提取tar压缩文件。tar -cvf 是创建对应压缩文件,tar -tvf 来查看对应压缩文件,tar -xvf 来提取对应压缩文件。gzip命令创建和提取gzip压缩文件,还可以用gzip -d 来提取压缩文件。help会在终端列出所有可用的命令,可以使用任何命令的-h或-help选项来查看该命令的具体用法。图就省略啦,会有详细列表显示出来的。whatis会用单行来描述给定的命令,就是解释当前命令。exit用于结束当前的终端会话。ping通过发送数据包ping远程主机(服务器),常用与检测网络连接和服务器状态。]]></content>
<categories>
<category>Linux</category>
<category>常用命令</category>
</categories>
<tags>
<tag>学习</tag>
<tag>兴趣</tag>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title><![CDATA[html基础]]></title>
<url>%2F2019%2F08%2F24%2Fhtml%2F</url>
<content type="text"><![CDATA[html基础学习一下页面的构造和前端的玩法学习自己写网页详情链接标签:内容:123451.由尖括号包裹单词构成,eg:<html>,所以标签不可能以数字开头2.标签不区分大小写,推荐小写3.标签可以嵌套,但不能交叉嵌套错误示例:<a><b></a></b>正确示例:<a><b></b></a>使用样式及属性:标签使用样式12开始标签<a >标签体</a>结束标签自闭合标签,eg:<br>,<hr>,<img>,<input>标签属性:12345a.通常为键值对形式出现,eg:color=“red” id = ‘eat’b.属性只能出现在开始标签和自闭和标签内c.属性名字全部小写,属性值必须用单引或者双引包裹d.如属性名和属性值完全一样,直接写属性名即可eg:“readonly”(input标签属性)html文件各部分标签详解123块级标签和内联标签块级标签:<p>/<h1>/<table>/<ol>/<ul>/<form>/<div>内联标签:<a>/<input/>/<img/>/<sub>/<sup>/<textarea>/<span>块级元素的特点:1234总在新行上开始高度,行高以及外边距和内边距都可控制宽度缺省,则是它容器的100%它可以容纳内联元素和其他块元素inline元素特点:1234和其他元素在一行上高,行高以及外边距和内边距不可改变宽度就是其文字或图片宽度,不可改变内联元素只能容纳文本或者其他内联元素行内元素注意:1234设置宽度width无效设置高度height无效设置margin只有左右margin有效,上下无效设置padding只有左右padding有效,上下则无效,注意元素范围是增大了,但是对元素周围的内容是没影响的。常用标签:块级标签12345总在新的一行上开始(会换行)标题标签(header):一般用在文章的标题,有h1~h6 (只有6级),会加粗<p>/<h1>/<table>/<ol>/<ul>/<form>/<div>123456789101112<p>:段落标签,换行<hn>:标题标签<table>:表格<ul>:无序标签<ol>:有序标签<form>:表单,用于提交数据/上传数据时候要把想要上传的内容写在form表单里面<div>:容器,用于分区和页面的整体布局段落标签(Paragraph):会把 HTML文档 分割成若干段落列表标签:分为:有序列表<ol>、无序列表<ul>以及自定义列表<dl>(含有列表<dt>与列表项<dd>)div标签:用于分化一个一个的区域px:像素行内标签1234567不管写多少行都在一行上图片标签<img src="图片的路径" alt="下载失败时的替换文字" title="鼠标移动到图片时的提示文字">,插入图片 :图片标签,用于向页面插入图片;图片格式:png,gif,jepg粗体<strong>/斜体 <em>:粗体标签将文字加粗,斜体标签将文字倾斜 <em>超链接标签<a href="跳转网址"></a>:超链接标签其实就是 a 标签,一般用于网页之间的跳转还能做锚点,进行跳转。网页之间的跳转,还可以进行本页之间的跳转.<a href=“目标网址” title=“鼠标滑过显示的文本” target=“_blank”(用于指定实在本页还是新的网页打开的)>链接显示的文本</a> :实现网页跳转和本页内跳转(要注意目标网址的区别)文字标签:Span 标签是单纯的文字标签,只有配合 CSS 才能有效果]]></content>
<categories>
<category>html</category>
</categories>
<tags>
<tag>学习</tag>
<tag>兴趣</tag>
<tag>html</tag>
</tags>
</entry>
<entry>
<title><![CDATA[atom配置gcc环境]]></title>
<url>%2F2019%2F08%2F22%2FAtom%E9%85%8D%E7%BD%AEgcc%E7%8E%AF%E5%A2%83%2F</url>
<content type="text"><![CDATA[Atom本篇主要介绍一下atom关于gcc的配置安装gcc/g++win7或者win10,在前面都是一样的,首先去官网下载mingw-get-setup.exe下载链接如图,点击这个下载即可。下载之后直接打开会出现下面这样下面这一步想改路径的可以该路径,不想改的直接无脑continue或者next就行了,如果改变了路径,要记住改到哪里了,后面要用到等待安装安装完下面的窗口会自动弹出来,按照步骤安装即可win7的话,按下面步骤安装,win10的话往下面看找到path,选中后点击编辑在后面添加;C:\MinGW\bin,这个英文的分好不能少了win10的就简单了,前面打开步骤相同,这一步直接新建添加就行PS:如果么没有成功就看一下是不是哪一步操作失误了,应该不会错吧,哈哈]]></content>
<categories>
<category>资源</category>
<category>教程</category>
</categories>
<tags>
<tag>学习</tag>
<tag>资源</tag>
<tag>兴趣</tag>
<tag>教程</tag>
</tags>
</entry>
<entry>
<title><![CDATA[装逼神器之atom]]></title>
<url>%2F2019%2F08%2F22%2FAtom%2F</url>
<content type="text"><![CDATA[Atom本篇主要介绍一下好用的编译器->atom下载atom安装链接下载完成就好了配置atom下载完成之后你可能会一脸懵逼但是没关系,我已经经历过的东西当然不可能让正在看的你也经历这种事情,嘿嘿嘿首先点击左上角的File,找到settings.进去,点到install里面接下来就是我们的为所欲为了PS:你要知道一点的是:atom是文本编译器,不要想着什么东西都给你配置好了,atom的美观度取决于你在这上面下了多少工夫好的,废话不多说,直接上一些我认为比较好的插件插入一下,如果不想看配置gcc就直接跳过下面这一阶段就好配置gcc/g++用到的软件下载链接然后就进去这个地方看如何配置环境,在此就不多写了配置完后(注意一定要先配置完环境)gcc插件一共有linter-gcc,linter,gcc-make-run三个插件去settings,然后install,搜索linter-gcc和linter安装PS:如果没有安装成功,多试验几次就好然后进入packages里面找到刚刚安装好的linter-gcc,进入这个插件的settings,将路径(带Path的一遍表示路径)改为g++或者gcc(如果环境没有配置好,你就gg了),勾选Lint on-the-fly这句表示在书写的同时进行编译(如果不勾选的话,只有在保存的时候才会编译)OK了,这个时候在安装一个可以让我们编写的代码能够运行的插件就大功告成了,老办法,安装gcc-make-run,安装完,按F6就OK了该介绍装逼的插件了Activate Power Mode:写代码效果很好(亲测),安装完就能用minimap:用过subline的应该都知道这个吧,不知道也没事,就是给一个缩小版的代码Emmet:Web开发者必不可少的工具,都说是神器color-picker:取色器atom-html-preview:实时预览HTML页面language-JavaScript-jsx:支持JSX语法vim-mode:用过vim的都知道好,基本实现了大部分的功能,不过造成许多快捷键冲突,这也是其他编辑器不具备的功能1234git-plus:git的插件与Sublime Text 的sublimegit功能基本一致,命令控制面板快捷键MacOS快捷键:Cmd+Shift+HWindows + Linux快捷键:Ctrl+Shift+Hfile-icons:让文件前面边好看点的图片docblockr:方便写代码注释autocomplete-plus:当输入的时候,提供可能的候选项simplified-chinese-menu:ATOM的汉化插件atom-beautify:代码格式一键美化last-cursor-position:光标自由切换到上一次/下一次编辑位置markdown-preview-plus:markdown预览quick-highlight:代码高亮advanced-open-file:快速的打开文件或新建文件,同时支持路径补全regex-railroad-diagram:正则表达式图形化autocomplete-paths:填写路径的时候有提示]]></content>
<categories>
<category>资源</category>
<category>教程</category>
</categories>
<tags>
<tag>学习</tag>
<tag>资源</tag>
<tag>兴趣</tag>
<tag>教程</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day30]]></title>
<url>%2F2019%2F08%2F19%2FDay30%2F</url>
<content type="text"><![CDATA[Day30今天学到的是网络流之最大流好好学习!!!链式前向星传送门网络流之最大流传送门Drainage DitchesDescription:Every time it rains on Farmer John’s fields, a pond forms over Bessie’s favorite clover patch. This means that the clover is covered by water for awhile and takes quite a long time to regrow. Thus, Farmer John has built a set of drainage ditches so that Bessie’s clover patch is never covered in water. Instead, the water is drained to a nearby stream. Being an ace engineer, Farmer John has also installed regulators at the beginning of each ditch, so he can control at what rate water flows into that ditch.Farmer John knows not only how many gallons of water each ditch can transport per minute but also the exact layout of the ditches, which feed out of the pond and into each other and stream in a potentially complex network.Given all this information, determine the maximum rate at which water can be transported out of the pond and into the stream. For any given ditch, water flows in only one direction, but there might be a way that water can flow in a circle.InputThe input includes several cases. For each case, the first line contains two space-separated integers, N (0 <= N <= 200) and M (2 <= M <= 200). N is the number of ditches that Farmer John has dug. M is the number of intersections points for those ditches. Intersection 1 is the pond. Intersection point M is the stream. Each of the following N lines contains three integers, Si, Ei, and Ci. Si and Ei (1 <= Si, Ei <= M) designate the intersections between which this ditch flows. Water will flow through this ditch from Si to Ei. Ci (0 <= Ci <= 10,000,000) is the maximum rate at which water will flow through the ditch.OutputFor each case, output a single integer, the maximum rate at which water may emptied from the pond.123456789Sample Input5 41 2 401 4 202 4 202 3 303 4 10Sample Output50code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889#include<bits/stdc++.h>using namespace std;typedef long long ll;const ll INF = 0x3f3f3f3f;const ll maxn = 1e6+10;ll n,m,s,t,u,v,w,cnt;struct edge{ ll to,dis,nxt;}G[maxn];ll head[maxn],d[maxn],cur[maxn];void add(ll from,ll to,ll dis){ G[cnt].to=to; G[cnt].dis=dis; G[cnt].nxt=head[from]; head[from]=cnt++;}ll dfs(ll u,ll flow){ if(u==t) return flow; ll x=0; for(ll i=cur[u];i!=-1;i=G[i].nxt) { cur[u]=G[i].nxt; ll v=G[i].to; if(d[v]==d[u]+1&&G[i].dis>0) { ll res=dfs(v,min(flow,G[i].dis)); flow-=res; x+=res; G[i].dis-=res; G[i^1].dis+=res; if(flow==0) break; } } if(!x) d[u]=-1; return x;}void bfs(){ memset(d,-1,sizeof(d)); queue<ll> que; que.push(s); d[s]=0; while(!que.empty()) { ll u=que.front();que.pop(); for(ll i=head[u];i!=-1;i=G[i].nxt) { ll v=G[i].to; if(d[v]==-1&&G[i].dis>0) { d[v]=d[u]+1; que.push(v); } } }}void dinic(){ ll max_flow=0; while(1) { bfs(); if(d[t]==-1) break; for(ll i=1;i<=n;i++) cur[i]=head[i]; max_flow+=dfs(s,INF); } cout<<max_flow<<endl;}int main(){ while(cin>>m>>n) { s=1,t=n; memset(head,-1,sizeof(head)); cnt=0; for(ll i=0;i<m;i++) { cin>>u>>v>>w; add(u,v,w); add(v,u,0); } dinic(); } return 0;}Island TransportDescription:In the vast waters far far away, there are many islands. People are living on the islands, and all the transport among the islands relies on the ships.You have a transportation company there. Some routes are opened for passengers. Each route is a straight line connecting two different islands, and it is bidirectional. Within an hour, a route can transport a certain number of passengers in one direction. For safety, no two routes are cross or overlap and no routes will pass an island except the departing island and the arriving island. Each island can be treated as a point on the XY plane coordinate system. X coordinate increase from west to east, and Y coordinate increase from south to north.The transport capacity is important to you. Suppose many passengers depart from the westernmost island and would like to arrive at the easternmost island, the maximum number of passengers arrive at the latter within every hour is the transport capacity. Please calculate it.InputThe first line contains one integer T (1<=T<=20), the number of test cases.Then T test cases follow. The first line of each test case contains two integers N and M (2<=N,M<=100000), the number of islands and the number of routes. Islands are number from 1 to N.Then N lines follow. Each line contain two integers, the X and Y coordinate of an island. The K-th line in the N lines describes the island K. The absolute values of all the coordinates are no more than 100000.Then M lines follow. Each line contains three integers I1, I2 (1<=I1,I2<=N) and C (1<=C<=10000) . It means there is a route connecting island I1 and island I2, and it can transport C passengers in one direction within an hour.It is guaranteed that the routes obey the rules described above. There is only one island is westernmost and only one island is easternmost. No two islands would have the same coordinates. Each island can go to any other island by the routes.OutputFor each test case, output an integer in one line, the transport capacity.1234567891011121314151617181920212223242526272829303132Sample Input25 73 33 03 10 04 51 3 32 3 42 4 31 5 64 5 31 4 43 4 26 7-1 -10 10 21 01 12 31 2 12 3 64 5 55 6 31 4 62 5 53 6 4Sample Output96code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697#include<bits/stdc++.h.>using namespace std;const int N = 100010;const int INF = 0x3f3f3f3f;typedef long long ll;int n,m,start,over;int deep[N],maxflow;struct edge{ int to,w,pre;}a[N<<2];int cnt=-1,head[N];void add(int from,int to,int w){ a[++cnt].to=to; a[cnt].w=w; a[cnt].pre=head[from]; head[from]=cnt;}bool bfs()//这里我们不用队列直接用数组代替{ memset(deep,-1,sizeof(deep)); int q[N<<1]; int fro,bac; fro=bac=0; q[bac++]=start,deep[start]=0; while(fro<bac) { int first=q[fro]; if(first==over) return 1; for(int i=head[first];~i;i=a[i].pre) { if(deep[a[i].to]==-1&&a[i].w>0) { deep[a[i].to]=deep[first]+1; q[bac++]=a[i].to; } } fro++; } return 0;}int dfs(int s,int cap){ if(s==over) return cap; int flow=0,f; for(int i=head[s];~i;i=a[i].pre) { int to=a[i].to; if(deep[to]==deep[s]+1&&a[i].w) { f=dfs(to,min(cap-flow,a[i].w)); a[i].w-=f; a[i^1].w+=f; flow+=f; if(flow==cap) break; } } if(flow==0) deep[s]=-2; return flow;}void dinic(){ int tem=0; while(bfs()) while((tem=dfs(start,INF))>0) maxflow+=tem;}int main(){ int t; scanf("%d",&t); while(t--) { maxflow=0,cnt=-1; memset(head,-1,sizeof(head)); scanf("%d %d",&n,&m); start = over = 1; int x,y,z,x_min=INF,x_max=-INF; for(int i=1;i<=n;i++) { scanf("%d %d",&x,&y); if(x<x_min) start=i,x_min=x; if(x>x_max) over=i,x_max=x; } for(int i=1;i<=m;i++) { scanf("%d %d %d",&x,&y,&z); add(x,y,z); add(y,x,z); } dinic(); cout<<maxflow<<endl; } return 0;}Power NetworkDescription:A power network consists of nodes (power stations, consumers and dispatchers) connected by power transport lines. A node u may be supplied with an amount s(u) >= 0 of power, may produce an amount 0 <= p(u) <= p max(u) of power, may consume an amount 0 <= c(u) <= min(s(u),c max(u)) of power, and may deliver an amount d(u)=s(u)+p(u)-c(u) of power. The following restrictions apply: c(u)=0 for any power station, p(u)=0 for any consumer, and p(u)=c(u)=0 for any dispatcher. There is at most one power transport line (u,v) from a node u to a node v in the net; it transports an amount 0 <= l(u,v) <= l max(u,v) of power delivered by u to v. Let Con=Σ uc(u) be the power consumed in the net. The problem is to compute the maximum value of Con.An example is in figure 1. The label x/y of power station u shows that p(u)=x and p max(u)=y. The label x/y of consumer u shows that c(u)=x and c max(u)=y. The label x/y of power transport line (u,v) shows that l(u,v)=x and l max(u,v)=y. The power consumed is Con=6. Notice that there are other possible states of the network but the value of Con cannot exceed 6.InputThere are several data sets in the input. Each data set encodes a power network. It starts with four integers: 0 <= n <= 100 (nodes), 0 <= np <= n (power stations), 0 <= nc <= n (consumers), and 0 <= m <= n^2 (power transport lines). Follow m data triplets (u,v)z, where u and v are node identifiers (starting from 0) and 0 <= z <= 1000 is the value of l max(u,v). Follow np doublets (u)z, where u is the identifier of a power station and 0 <= z <= 10000 is the value of p max(u). The data set ends with nc doublets (u)z, where u is the identifier of a consumer and 0 <= z <= 10000 is the value of c max(u). All input numbers are integers. Except the (u,v)z triplets and the (u)z doublets, which do not contain white spaces, white spaces can occur freely in input. Input data terminate with an end of file and are correct.OutputFor each data set from the input, the program prints on the standard output the maximum amount of power that can be consumed in the corresponding network. Each result has an integral value and is printed from the beginning of a separate line.12345678910Sample Input2 1 1 2 (0,1)20 (1,0)10 (0)15 (1)207 2 3 13 (0,0)1 (0,1)2 (0,2)5 (1,0)1 (1,2)8 (2,3)1 (2,4)7 (3,5)2 (3,6)5 (4,2)7 (4,3)5 (4,5)1 (6,0)5 (0)5 (1)2 (3)2 (4)1 (5)4Sample Output156HintThe sample input contains two data sets. The first data set encodes a network with 2 nodes, power station 0 with pmax(0)=15 and consumer 1 with cmax(1)=20, and 2 power transport lines with lmax(0,1)=20 and lmax(1,0)=10. The maximum value of Con is 15. The second data set encodes the network from figure 1.code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103#include<iostream>#include<cstdio>#include<queue>#include<cstring>const int INF = 0x3f3f3f3f;const int maxn = 2e5;using namespace std;struct edge{ int to,dis,nxt;}G[maxn];int head[maxn],d[maxn];int n,np,nc,m,cnt,s,t;void add(int from,int to,int dis){ G[cnt].to=to; G[cnt].dis=dis; G[cnt].nxt=head[from]; head[from]=cnt++;}int bfs(){ memset(d,-1,sizeof(d)); d[s]=0; queue<int> q; q.push(s); while(!q.empty()) { int u=q.front(); if(u==t) return 1; q.pop(); for(int i=head[u];i!=-1;i=G[i].nxt) { int v=G[i].to; int dis=G[i].dis; if(dis&&d[v]==-1) { d[v]=d[u]+1; q.push(v); } } } return 0;}int dfs(int u,int flow){ if(u==t) return flow; int x=0; for(int i=head[u];i!=-1;i=G[i].nxt) { int v=G[i].to; int dis=G[i].dis; if(dis&&d[v]==d[u]+1) { int f=dfs(v,min(dis,flow-x)); G[i].dis-=f; G[i^1].dis+=f; x+=f; if(x==flow) return x; } } return x;}void dinic(){ int ans=0; while(bfs()) { ans+=dfs(s,INF); } cout<<ans<<endl;}int main(){ while(~scanf("%d%d%d%d",&n,&np,&nc,&m)) { cnt=0; s=n+1; t=s+1; memset(head,-1,sizeof(head)); for(int i=0;i<m;i++) { int x,y,w; scanf(" (%d,%d)%d",&x,&y,&w); add(x,y,w); add(y,x,0); } for(int i=0;i<np;i++) { int v,w; scanf(" (%d)%d",&v,&w); add(s,v,w); add(v,s,0); } for(int i=0;i<nc;i++) { int u,w; scanf(" (%d)%d",&u,&w); add(u,t,w); add(t,u,0); } dinic(); }}PathDescription:Years later, Jerry fell in love with a girl, and he often walks for a long time to pay visits to her. But, because he spends too much time with his girlfriend, Tom feels neglected and wants to prevent him from visiting her.After doing some research on the neighbourhood, Tom found that the neighbourhood consists of exactly n houses, and some of them are connected with directed road. To visit his girlfriend, Jerry needs to start from his house indexed 1 and go along the shortest path to hers, indexed n.Now Tom wants to block some of the roads so that Jerry has to walk longer to reach his girl’s home, and he found that the cost of blocking a road equals to its length. Now he wants to know the minimum total cost to make Jerry walk longer.Note, if Jerry can’t reach his girl’s house in the very beginning, the answer is obviously zero. And you don’t need to guarantee that there still exists a way from Jerry’s house to his girl’s after blocking some edges.InputThe input begins with a line containing one integer T(1≤T≤10), the number of test cases.Each test case starts with a line containing two numbers n,m(1≤n,m≤10000), the number of houses and the number of one-way roads in the neighbourhood.m lines follow, each of which consists of three integers x,y,c(1≤x,y≤n,1≤c≤109), denoting that there exists a one-way road from the house indexed x to y of length c.OutputPrint T lines, each line containing a integer, the answer.123456789Sample Input13 41 2 12 3 11 3 21 3 3Sample Output3code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154//EK算法求解最大流#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>#include<queue>#define ll long longusing namespace std;const ll inf = 34338315071127552;int n,m,s,t;struct Node{ ll v; ll val; ll next;}node[20101];int top=1,head[10101];//top必须从一个奇数开始,一般用-1但我不习惯,解释见下方void init(int n){ memset(head,-1,sizeof(int)*(n+1)); top = 1;}inline void addedge(ll u,ll v,ll val){ node[++top].v=v; node[top].val=val; node[top].next=head[u]; head[u]=top;}inline int Read(){ int x=0; char c=getchar(); while(c>'9'||c<'0')c=getchar(); while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar(); return x;}ll inque[10101];//点是访问过里struct Pre{ ll v;//该点的前一个点(从起点过来) ll edge;//与该点相连的边(靠近起点的)}pre[10101];inline bool bfs(){ queue<ll>q; memset(inque,0,sizeof(inque)); memset(pre,-1,sizeof(pre)); inque[s]=1; q.push(s); while(!q.empty()){ ll u=q.front(); q.pop(); for(int i=head[u];i;i=node[i].next){ ll d=node[i].v; if(!inque[d]&&node[i].val){//node[i].val==0则已经该路径满了 pre[d].v=u; pre[d].edge=i; if(d==t)return 1; inque[d]=1; q.push(d); } } } return 0;}//是否有增广路ll EK(){ ll ans=0; while(bfs()){ ll mi=inf; for(int i=t;i!=s;i=pre[i].v){ mi=min(mi,node[pre[i].edge].val);//每次只能增加增广路上最小的边的权值 } for(int i=t;i!=s;i=pre[i].v){ node[pre[i].edge].val-=mi; node[pre[i].edge^1].val+=mi; //反向的边的编号是正向边的编号^1 //这就是为什么top开始时必须是奇数 } ans+=mi; } return ans;}const int maxn = 1e4 + 10;typedef pair<ll,ll> pii;vector<pii> G[maxn];ll dis[maxn];void djk(int n){ for (int i = 0;i <= n+1;i ++) dis[i] = inf; priority_queue<pii,vector<pii>,greater<pii> > que; dis[1] = 0; que.push({0,1}); while (!que.empty()) { pii p = que.top(); ll v = p.second; que.pop(); if (dis[v] < p.first) continue; for (int i = 0;i < G[v].size();i ++) { pii p2 = G[v][i]; if (dis[p2.first] > dis[v] + p2.second) { dis[p2.first] = dis[v] + p2.second; que.push({dis[p2.first],p2.first}); } } }}int main(){ int num; scanf("%d",&num); while (num --) { //int n,m; scanf("%d %d",&n,&m); for (int i = 1;i <= n;i ++) G[i].clear(); init(n); for (int i = 1;i <= m;i ++) { ll u,v,w; scanf("%lld %lld %lld",&u,&v,&w); G[u].push_back({v,w}); } djk(n); m = 0; for (int i = 1;i <= n;i ++) { for (int j = 0;j < G[i].size();j ++) { pii p = G[i][j]; if (dis[i] + p.second == dis[p.first]) { //cout<<"u\t"<<i<<"\tv\t"<<p.first<<"\tw\t"<<p.second<<endl; addedge(i,p.first,p.second); addedge(p.first,i,0); m ++; } } } s = 1,t = n; ll ans = EK(); printf("%lld\n",ans); if (!ans) cout<<"dis\t"<<dis[n]<<endl; } return 0;}//7 8//1 2 2//1 3 1//2 4 1//3 4 2//4 5 1//4 6 2//5 7 1//6 7 1]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>链式前向星</tag>
<tag>网络流</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day29]]></title>
<url>%2F2019%2F08%2F18%2FDay29%2F</url>
<content type="text"><![CDATA[Day29今天学长的积分赛好好学习!!!分数Description:Anxdada有一个长度为n的非负整数序列a1, a2, …, an.他想知道能否将这个序列划分成奇数个子序列,其中每个子序列的第一个数字是奇数,最后一个数字也是奇数,而且这个子序列的长度也是奇数子序列就是原序列的一个连续的片段. 例如,{3, 4, 5}和{1}都是{1, 2, 3, 4, 5, 6}的子序列,但是{1, 2, 4}和{7}并不是{1, 2, 3, 4, 5, 6}的子序列Input第一行包含一个正整数n(1 ≤ n ≤ 100) — 原序列的长度.第二行包含n个非负整数a1, a2, …, an (0 ≤ ai ≤ 100) — 这个序列的元素.Output如果原序列可以按要求进行划分就输出”Yes”,否则输出”No”.12345678910111213141516171819202122232425Simple Input 131 3 5Simple Output 1YesSimple Input 251 0 1 5 1Simple Output 2YesSimple Input 334 3 1Simple Output 3NoSimple Input 443 9 9 3Simple Output 4NoNote在第一个样例中,把原序列划分为1个子序列: {1, 3, 5}满足题目的要求.在第二个样例中,把原序列划分为3个子序列: {1, 0, 1}, {5}, {1}.在第三个样例中,其中一个子序列一定以4开头,但是4是偶数,因此不符合题意.在第四个样例中,把原序列划分为2个部分:{3, 9, 9},{3},但是2是偶数不满足题意.code:1234567891011121314151617#include<bits/stdc++.h>using namespace std;int a[110];int main(){ int t; scanf("%d",&t); for(int i = 1; i <= t; i ++) scanf("%d",&a[i]); if(t % 2 == 0) puts("NO"); else { if((a[1] & 1) && (a[t] & 1)) puts("YES"); else puts("NO"); } return 0;}搜索漂亮的整数Description:小红现在有两个列表的数字.如果一个十进制数至少有一个数字来自列表一且至少有一个数字来自列表二,那么将这个数字叫做小红数,请你找出最小的正小红数Input第一行包括两个整数 n 和 m (1 ≤ n, m ≤ 9) — 分别代表第一个和第二个列表的长度。第二行包含 n 个不同的数字 a1, a2, …, an (1 ≤ ai ≤ 9) 代表列表一中的元素。第三行包含 m 个不同的数字 b1, b2, …, bm (1 ≤ bi ≤ 9) 代表列表二中的元素Output输出最小正小红数.12345678910111213ExampleInput2 34 25 7 6Output25Input8 81 2 3 4 5 6 7 88 7 6 5 4 3 2 1Output1code:1234567891011121314151617181920212223242526272829303132333435363738#include<bits/stdc++.h>using namespace std;const int maxx = 20;int a[maxx], b[maxx];int main(){ ios::sync_with_stdio(false); int n, m; int minn, maxn; cin >> n >> m; for(int i = 0; i < n; i ++) cin >> a[i]; for(int i = 0; i < m; i ++) cin >> b[i]; sort(a, a + n); sort(b, b + m); int ans = 0; int flag = 0; for(int i = 0; i < n; i ++) { for(int j = 0; j < m; j ++) { if(a[i] == b[j]) { ans = a[i]; flag = 1; break; } } if(flag) break; } if(flag) cout << ans << '\n'; else { minn = min(a[0], b[0]); maxn = max(a[0], b[0]); cout << minn * 10 + maxn << '\n'; } return 0;}hzy 和zsl 的生存挑战Description:zsl 和hzy 来到了臭臭城堡,打算挑战臭臭城堡的大魔王hyz,大魔王hyz设置了这样的一个挑战:zsl 和hzy两个人各自来到一间密室,期间两人无法以任何形式交流大魔王hyz会随机在两个人的脑海里各发送一个数字,0或者是1zsl 和 hzy 需要猜对这俩个数字才算通关,但是大魔王hyz觉得人生不能过于无敌,因此降低难度,只要两个人中有一个人答对就算是通关现在大魔王hyz 给出的数字可能的情况有 00, 01, 10, 11 四种,请按上述枚举的顺序,计算所有情况下zsl 和hzy 通关的几率。(假设zsl 和 hzy 两个人都足够机智,能够选择出最优决策)Input(空)Output输出四个答案,每个答案后面跟随一个换行符并且保留两位小数位,分别对应00,01,10,11的情况下,zsl和hzy通关的几率1234567Sample Input(空)Sample Output1.000.000.500.55 (输出仅做格式参考,不保证正确性)评价该题及其SB,不得不吐槽一下code:12345678910#include<bits/stdc++.h>using namespace std;int main(){ printf("1.00\n1.00\n1.00\n1.00\n"); return 0;}共享单车Description:学长自从上次被打了一顿之后,就想着讨好实验室的人。于是他决定带着实验室的人出去玩。实验室一共有k个人,出去玩需要骑自行车。一共有m家共享单车公司提供自行车,第i家共享单车公司提供的自行车信息用li,ri,ci,pi表示。其中:li,ri表示这家公司从接下来的第li天到ri天,提供共享单车.ci表示这家公司在这些天每天提供的单车数目.pi表示租用每辆车需要的单价.现在学长想在接下来连续的n天,每天都带着实验室的k个人出去玩,要求出行时候每个人都尽可能能坐到单车,即每天都要租k辆车,当然如果某一天所有公司全部加起来都没有提供k辆车,那么就将所有车都租下,让剩下的一些人走路,否则如果够k辆就一定要租k辆.请你输出学长最少需要花多少钱.Input输入的第一行为3个整数n,k,m(1<=n,k<=10^6,1<=m<=2*10^5).接下来m行,每行4个整数li,ri,ci,pi(1<=li<=ri<=n,1<=ci,pi<=10^6).Output输出只有一行,表示学长最少需要花费的钱.题意有很多个活动,每个活动有持续天数,每个活动会在每天提供C个CPU每个CPU价格为P,问需要工作N天,每天需要K个CPU的最少花费。解题思路首先价格越低的活动,肯定是要选的。因此我们对于每一天记录有哪些新活动 加入,哪些活动结束。然后维护一个线段树,线段树的下标是价格。即价格为i的活动,一共能提供多少个CPU,然后加入和删除活动就相当于update(C,+-P,1,MAXC,1)。 然后我们顺便维护一下价格*数量的和。然后利用线段树天然的二分性,快速求出前缀数量和为K的价格和。1234567891011121314151617ExamplesInput5 7 31 4 5 31 3 5 22 5 10 1Output44Input7 13 52 3 10 73 5 10 101 2 10 64 5 10 93 4 10 8Output462code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990#include <iostream>#include <algorithm>#include <string.h>#include <vector>#include <memory.h>#include <bitset>#include <map>#include <deque>#include <math.h>#include <stdio.h>using namespace std;typedef long long int ll;const int MAXN = 1000005;ll num[MAXN<<2];ll sum[MAXN<<2];int N;void pushup(int rt){ num[rt]=num[rt<<1]+num[rt<<1|1]; sum[rt]=sum[rt<<1]+sum[rt<<1|1];}void update(int P,int C,int l,int r,int rt){ if(l==r){ num[rt]+=C; sum[rt]+=1ll*P*C; return; } int m=(l+r)/2; if(P<=m) update(P,C,l,m,rt<<1); else update(P,C,m+1,r,rt<<1|1); pushup(rt);}ll query(int K,int l,int r,int rt){ if(l==r){ //不到K个 if(l==MAXN){ return 0; } if(K>0) { return 1ll*K*l; } else return 0; } int m=(l+r)/2; if(num[rt<<1]>=K){ return query(K,l,m,rt<<1); } else{ return sum[rt<<1]+query(K-num[rt<<1],m+1,r,rt<<1|1); }}vector<pair<int,int> > C[MAXN];//第i天加入的活动vector<pair<int,int> > O[MAXN];//第i天结束的活动int main(){ int K,M; scanf("%d%d%d",&N,&K,&M); int l,r,c,p; for(int i=0;i<M;i++){ scanf("%d%d%d%d",&l,&r,&c,&p); C[l].push_back(make_pair(p,c));//加入的活动 O[r].push_back(make_pair(p,c));//退出的活动 } ll ans=0; for(int i=1;i<=N;i++){ //新活动加入 for(int j=0;j<C[i].size();j++) update(C[i][j].first,C[i][j].second,1,MAXN,1); ans+=query(K,1,MAXN,1); //活动结束 for(int j=0;j<O[i].size();j++) update(O[i][j].first,-O[i][j].second,1,MAXN,1); } cout<<ans<<endl; return 0;}最小值最大值Description:给出一个有n个整数的数组 a1, a2, …, an 和一个整数k。你被要求把这个数组分成k 个非空的子段。 然后从每个k 个子段拿出最小值,再从这些最小值中拿出最大值。求这个最大值最大能为多少?Input第一行输入两个整数 n 和 k (1 ≤ k ≤ n ≤ 105) — 数组a 的大小和要求分成子段的数目第二行包含 n 整数 a1, a2, …, an ( - 109 ≤ ai ≤ 109).Output输出答案——在你分离的每个子段中最小值中的最大值k1234567891011ExampleInput5 21 2 3 4 5Output5Input5 1-4 -5 -3 -2 -1Output-5PS:对2也要特判一下code:12345678910111213141516171819#include<bits/stdc++.h>using namespace std;typedef long long ll;ll a[100001];int main(){ int n, k; scanf("%d %d",&n, &k); for(int i = 1; i <= n; i ++) scanf("%lld",&a[i]); if(k == 2) cout << max(a[1], a[n]) << '\n'; else { sort(a + 1, a + n + 1); if(k == 1) cout << a[1] << '\n'; else cout << a[n] << '\n'; } return 0;}RingDescription:邓布利多教授正在帮助哈利摧毁魂器。当他怀疑一个魂器出现在那里时,他去了冈特沙克。他看到Marvolo Gaunt的戒指,并将其确定为魂器。虽然他摧毁了它,但仍然受到诅咒的影响。斯内普教授正在帮助邓布利多解除诅咒。为此,他想给Dumbledore提供他制作的药水x滴。x的值被计算为给定p,q,r和阵列a1,a2,……的p·ai + q·aj + r·ak的最大值,使得1≤i≤j≤k≤n。帮助Snape找到x的值。请注意x的值可能是负数。Input第一行输入包含4个整数n,p,q,r( - 1e9≤p,q,r≤1e9, 1≤n≤1e5)。下一行输入包含n个空格分隔的整数a1,a2,… an( - 1e9≤ai≤1e9)。Output输出p≤ai+ q·aj + r·ak的最大值,只要1≤i≤j≤k≤n即可得到。123456789101112131415ExamplesInput5 1 2 31 2 3 4 5Output30Input5 1 2 -3-1 -2 -3 -4 -5Output12NoteIn the first sample case, we can take i = j = k = 5, thus making the answer as 1·5 + 2·5 + 3·5 = 30.In second sample case, selecting i = j = 1 and k = 5 gives the answer 12.题解找到a[i]p+a[j]q+a[k]*r的最大值,i<=j<=k;code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546//每次更新#include<stdio.h>#include<iostream>using namespace std;int main(){ long long n,a1,a2,a3,a=-8e18,b=-8e18,c=-8e18; cin>>n>>a1>>a2>>a3; int x; for(int i=0;i<n;i++) { cin>>x; a=max(a,a1*x); b=max(b,a+a2*x); c=max(c,b+a3*x); } cout<<c<<endl;}//前后缀维护#include<bits/stdc++.h>using namespace std;const int N = 100005;int a[N];long long L[N],R[N];int main(){ ios_base::sync_with_stdio(0); cin.tie(0); int n; long long p,q,r; cin >> n >> p >> q >> r; for(int i = 1;i <= n;i++) cin >> a[i]; L[1] = a[1]*p;R[n] = a[n]*r; for(int i = 2;i <= n;i++) L[i] = max(L[i-1],a[i]*p); for(int i = n-1;i >= 1;i--) R[i] = max(R[i+1],a[i]*r); long long maxn = -(1ll<<63); for(int i = 1;i <= n;i++) maxn = max(maxn , L[i]+a[i]*q+R[i]); cout << maxn << "\n"; return 0;}赛题分析Description:著名出题人小Q每次比赛后都会写一份《赛题分析》,包含比赛概况、每题的参考算法以及一些统计数值。对于一道题来说,小Q会统计最短的验题人代码长度(Shortest judge solution)以及赛内参赛队伍最短的AC代码长度(Shortest team solution)。统计验题人代码长度比较容易,因为验题人最多也不会超过20个。但是统计选手代码长度就不容易了,因为大赛区动辄三四百支队伍。请写一个程序,帮助小Q统计最短代码长度。Input第一行包含一个正整数T(1≤T≤13),表示赛题数量。每道题第一行包含两个整数n,m(2≤n≤20,0≤m≤500),分别表示验题人数量以及AC了该题的队伍数量。第二行包含n个正整数a1,a2,…,an(50≤ai≤65536),依次表示每个验题人的代码字节数。第三行包含m个正整数b1,b2,…,bn(50≤bi≤65536),依次表示每支AC队伍的代码字节数。若m=0则该行为空行。Output对于第i(1≤i≤T)道题,输出三行,第一行输出Problem x:,其中x=i+1000。第二行输出Shortest judge solution: y bytes.,其中y表示最短的验题人代码字节数。第三行输出Shortest team solution: z bytes.,其中z表示最短的选手代码字节数,若不存在请输出N/A。注意:间隔都是一个空格。1234567891011121314Sample Input23 23627 1460 52882365 26712 05510 7682Sample OutputProblem 1001:Shortest judge solution: 1460 bytes.Shortest team solution: 2365 bytes.Problem 1002:Shortest judge solution: 5510 bytes.Shortest team solution: N/A bytes.排序题code:1234567891011121314151617181920212223242526#include<bits/stdc++.h>using namespace std;int a[30], b[600];int main(){ int t; int n, m; scanf("%d",&t); int k = 1001; while(t --) { scanf("%d %d",&n, &m); for(int i = 0; i < n; i ++) scanf("%d",&a[i]); for(int i = 0; i < m; i ++) scanf("%d",&b[i]); sort(a, a + n); sort(b, b + m); printf("Problem %d:\n",k ++); printf("Shortest judge solution: %d bytes.\n",a[0]); if(m != 0) printf("Shortest team solution: %d bytes.\n",b[0]); else printf("Shortest team solution: N/A bytes.\n"); } return 0;}差异的可分割性Description:现在有n个整数,在这n个数中找出k个数,保证这k个数中任意两个数差的绝对值可以被m整除。Input第一行输入三个整数n,k,m(2<=k<=n<=100000,1<=m<=100000)。第二行包含n个整数a1,a2,…, an(0 <= ai <= 10^9 )。Output如果不存在这样的k个数,输出”No”;否则输出”Yes”后,在下一行输出这k个数,数与数之间用空格隔开。 (存在多种情况,输出任意一种)。123456789101112131415161718ExampleInput3 2 31 8 4OutputYes1 4Input3 3 31 8 4OutputNoInput4 3 52 7 7 7OutputYes2 7 7题解用数组记录每个数对m取模余数相等的有多少个code:12345678910111213141516171819202122232425262728293031323334353637#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int maxn = 1e5+5;int nu[maxn];int cnt[maxn];int main() { ios::sync_with_stdio(false); int n,k,m,i; cin>>n>>k>>m; for(i=1;i<=n;++i) { cin>>nu[i]; } int ans=-1; for(i=1;i<=n;++i) { int u=nu[i]%m; ++cnt[u]; if(cnt[u]==k) { ans=u; break; } } if(ans==-1) cout<<"No"<<endl; else { cout<<"Yes"<<endl; for(int i=1;i<=n;++i) { if(nu[i]%m==ans) { --k; cout<<nu[i]<<" "; } if(k==0) break; } } return 0;}扫雷Description:扫雷游戏是晨晨和小璐特别喜欢的智力游戏,她俩最近沉迷其中无法自拔。该游戏的界面是一个矩阵,矩阵中有些格子中有一个地雷,其余格子中没有地雷。 游戏中,格子可能处于己知和未知的状态。如果一个己知的格子中没有地雷,那么该 格子上会写有一个一位数,表示与这个格子八连通相邻的格子中地雷总的数量。现在,晨晨和小璐在一个3行N列(均从1开始用连续正整数编号)的矩阵中进 行游戏,在这个矩阵中,第2行的格子全部是己知的,并且其中均没有地雷;而另外 两行中是未知的,并且其中的地雷总数量也是未知的。晨晨和小璐想知道,第1行和第3行有多少种合法的埋放地雷的方案。Input包含多组测试数据,第一行一个正整数T,表示数据组数。每组数据由一行仅由数字组成的长度为N的非空字符串组成,表示矩阵有3行N 列,字符串的第i个数字字符表示矩阵中第2行第i个格子中的数字。保证字符串长度N <= 10000,数据组数<= 100。Output每行仅一个数字,表示安放地雷的方案数mod100,000,007的结果。1234567Sample Input222000Sample Output61题解这一题,你会发现确定了第一列的摆放方案,后面所有的都就确定了。。所以我们就枚举第一列的方案数,一共就有0,1,2三种,注意我们操作的是每一列,所以注意不能超过2个。。然后,模拟姿势就是,因为这个是身边的八个格子,枚举当前列的时候,我们要把它当成八个格子三列中的最后一列,以中间列为标准,设dp为枚举状态每一列已经放的个数,num为题目告诉的雷数,那么枚举每一列的时候,都要看前一列(八个格子三列中的中间列),用num[i-1]-dp[i-2]-dp[i-1],即减去中间列左面放的,自己这一列放的,就是右边放的了,这样就满足了num[i]的数量。。姿势很重要。。然后就是计数了,如果当前放了0个或者两个,i列跟i-1列的方案数是一样的,如果是1的话,那i列就是i-1列的两倍了。。code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>using namespace std;typedef long long ll;const int maxn = 1e4 + 5;const int Mod = 1e8 + 7;int num[maxn], dp[maxn];char str[maxn];int main(){ int t; scanf("%d", &t); while(t--) { memset(dp, 0, sizeof(dp)); scanf("%s", str); int n = strlen(str); for(int i = 0; i < n; i++) num[i+1] = str[i] - '0'; ll ans = 1, res = 0; for(int i = 0; i <= num[1]; i++) { ans = 1; if(i > 2) break; //控制条件 dp[1] = i; int j; for(j = 2; j <= n; j++) { int k = num[j-1] - dp[j-1] - dp[j-2]; if(k > 2 || k < 0) break; //控制条件,这些都容易漏 dp[j] = k; } if(j <= n) continue; if(dp[n-1] + dp[n] != num[n]) continue; //这里一定要有,区域赛的题好几题都是策略完了,然后要判定一下。。按照这个策略,看看最后两列是不是相同 for(int i = 1; i <= n; i++) { if(dp[i] == 1) ans = (ans * 2) % Mod; } res = (res + ans) % Mod; } printf("%lld\n", res); } return 0;}派对柠檬水Description:点完菜,他们发现好像觉得少了点什么?想想马上就要回老家了某不愿透露姓名的林姓学长再次却陷入了沉思。。。。。。。。。他默默的去前台打算点几瓶二锅头。他发现菜单上有n 种不同毫升的酒. 第 i 种有2i - 1 毫升价格为ci 元.商店中每种类型的酒的数量可以被认为是无限的。.他对于自己能喝多少还是有点B-Tree的,但是他认为喝酒一定要喝的尽兴,于是他打算买至少L 毫升,但是又要花最少的钱,现在他想知道他最少需要花多少钱Input第一行输入两个整数 n and L (1 ≤ n ≤ 30; 1 ≤ L ≤ 109) — 代表有n总酒和需要买的数量第二行输入 n个整数s c1, c2, …, cn (1 ≤ ci ≤ 109) —代表第i种酒需要的钱数Output输出一个整数,他买至少L 了毫升,所花的最少钱数123456789101112131415161718192021222324252627ExampleInput4 1220 30 70 90Output150Input4 310000 1000 100 10Output10Input4 310 100 1000 10000Output30Input5 787787787123456789 234567890 345678901 456789012 987654321Output44981600785557577Note在第一个例子中,你应该花90元购买一个8毫升的,花60元的购买两个2毫升的。总共你会得到12毫升只要150元。在第二个例子中,即使你只需要3毫升,但是购买一个10元8毫升的便宜一些。在第三个例子中,最好10元购买三个1毫升的。题目大意有 n 种柠檬汁,第 i 种每瓶的容量为 2^(i-1) 升,价格为 Ci,问至少买 L 升柠檬汁最少花多少钱?题解一看题,第一感觉是 DP,但是由于购买数可以超过 L 升,并且 L 太大了,所以不能用 DP解决。我们采取贪心的策略:优先买单价更低的。这样会出现一个问题,剩余量如果不够一瓶,我们是买一瓶单价最低的呢?还是从单价更高的中拼一下呢?因为买一瓶单价最低的话会产生一点浪费。所以我们就可以按照这个思路用 DFS做。code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>using namespace std;typedef long long LL;LL n,mn;struct node{ LL cost,lit; //每瓶的价格和容量 double v; //单价 /升} a[33];LL cmp(node a,node b){ return a.v<b.v;}void dfs(LL dep,LL res,LL ans){ //参数:当前位置,剩余量,当前花费 int f=0; if(ans>=mn) return; //如果当前花费比最小值大则退出 if(dep==n||res<=0) { //如果搜索完毕或者已经购买完,则更新最小值并退出 if(ans<mn) mn=ans; return; } LL x=res/a[dep].lit; //当前种柠檬汁可以买多少瓶 if(res%a[dep].lit!=0) { //如果剩余不够一瓶,则多买一瓶 x++; f=1; } ans+=x*a[dep].cost; //先多买一瓶当前种的 res-=x*a[dep].lit; dfs(dep+1,res,ans); if(f==1) { //如果多买了,则在回溯时还原 ans-=a[dep].cost; res+=a[dep].lit; dfs(dep+1,res,ans); }}int main(){ LL i,l; while(~scanf("%lld%lld",&n,&l)) { for(i=0;i<n;i++) { scanf("%lld",&a[i].cost); a[i].lit=1<<i; a[i].v=(double)a[i].cost/a[i].lit; } sort(a,a+n,cmp); //按单价升序排序 mn=0x7fffffffffffffff; dfs(0,l,0); printf("%lld\n",mn); } return 0;}CountDescription:Farmer John有n头奶牛.某天奶牛想要数一数有多少头奶牛,以一种特殊的方式:第一头奶牛为1号,第二头奶牛为2号,第三头奶牛之后,假如当前奶牛是第n头,那么他的编号就是2倍的第n-2头奶牛的编号加上第n-1头奶牛的编号再加上自己当前的n的三次方为自己的编号.现在Farmer John想知道,第n头奶牛的编号是多少,估计答案会很大,你只要输出答案对于123456789取模.Input第一行输入一个T,表示有T组样例接下来T行,每行有一个正整数n,表示有n头奶牛 (n>=3)其中,T=10^4,n<=10^18Output共T行,每行一个正整数表示所求的答案12345678910111213Sample Input53691215Sample Output31700748664651527023数据范围这么大,直接矩阵快速幂解决题意f[n] = 2*f[n-2] + f[n-1] + n^3,n<=1e18,求f[n] 。题解在计算 f[n+1] 的时候, 要变为 ,所以构造的矩阵中需要有这几项,然后因为引入了 ,所以 要变为 ,因为 项、项、常数项都已经存在,所以不需要引入新的项,其余各项均可通过这几项计算出。code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475#include<bits/stdc++.h>using namespace std;typedef long long ll;const int MAX = 1e6 + 20;const int mod = 123456789;ll n;typedef struct { ll m[10][10];}Matrix;Matrix Mul(Matrix a, Matrix b){ Matrix c; memset(c.m, 0, sizeof(c.m)); for (int i = 0; i < 6; i++) { for (int j = 0; j < 6; j++) { for (int k = 0; k < 6; k++) { c.m[i][j] += ((a.m[i][k] * b.m[k][j]) % mod + mod) % mod; c.m[i][j] %= mod; } } } return c;}Matrix fastm(Matrix a, ll num){ Matrix res; memset(res.m, 0, sizeof(res.m)); for (int i = 0; i < 6; i++) res.m[i][i] = 1; while (num) { if (num & 1) res = Mul(res, a); num >>= 1; a = Mul(a, a); } return res;}int main(){ int T; scanf("%d", &T); Matrix a; memset(a.m, 0, sizeof(a.m)); a.m[0][0] = 1, a.m[0][1] = 1; a.m[1][0] = 2; a.m[2][0] = 1, a.m[2][2] = 1; a.m[3][2] = 1, a.m[3][3] = 1; a.m[4][2] = 1, a.m[4][3] = 2, a.m[4][4] = 1; a.m[5][2] = 1, a.m[5][3] = 3, a.m[5][4] = 3, a.m[5][5] = 1; ll st[10]; st[0] = 2, st[1] = 1, st[2] = 27, st[3] = 27, st[4] = 9, st[5] = 1; while (T--) { scanf("%lld", &n); n -= 2; Matrix b = fastm(a, n); ll ans = 0; for (int i = 0; i < 6; i++) { ans = (ans + b.m[i][0] * st[i] % mod) % mod; } printf("%lld\n", ans); } return 0;}诊断Description:Hao得了重感冒。他将要去看 n 名医生来找出确切的诊断。每个医生都需要之前医生的所有的诊断信息,所以Hao需要按照规定的顺序访问医生(比如Hao应该先访问 1号医生,2号医生, 然后是3号医生,等等)。 Hao将从上一位医生那里获取关于他的健康信息。医生有一个奇怪的工作表。第i名医生从si天起工作之后会每隔di 天再工作.所以医生在si, si + di, si + 2di, ….这段时间是处以上班状态Hao一天只能访问一名医生,Hao访问完所有医生之后所花费的最短时间是多少?InputFirst line contains an integer n — number of doctors (1 ≤ n ≤ 1000).Next n lines contain two numbers si and di (1 ≤ si, di ≤ 1000).OutputOutput a single integer — the minimum day at which Borya can visit the last doctor.123456789101112131415161718ExampleInput32 21 22 2Output4Input210 16 5Output11NoteIn the first sample case, Borya can visit all doctors on days 2, 3 and 4.In the second sample case, Borya can visit all doctors on days 10 and 11.题目大意说的是找到最晚的一天,那就一只加呗,直到最后一天code:1234567891011121314151617181920212223242526272829303132333435#include<bits/stdc++.h>using namespace std;struct node{ int x, y;}e[1001];int main(){ int t; while(~scanf("%d",&t)) { for(int i = 1; i <= t; i ++) scanf("%d %d",&e[i].x, &e[i].y); int ans = e[1].x; for(int i = 2; i <= t;) { if(e[i].x > ans) { ans = e[i].x; i ++; } else { while(e[i].x <= ans) { e[i].x += e[i].y; } } } printf("%d\n",ans); } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day28]]></title>
<url>%2F2019%2F08%2F17%2FDay28%2F</url>
<content type="text"><![CDATA[Day28今天积分赛好好学习!!!Steve的水池Description:Steve 拥有深棕色头发,晒黑的褐色皮肤,紫色的眼睛,身穿青蓝色的衬衫,一条紫蓝色牛仔裤以及灰黑色的鞋子。他还拥有2px至4px大小的胳膊。Steve 似乎拥有轻微的浅棕色胡子茬,或者拥有一张嘴,这取决于你怎样看他。Steve 需要种庄稼,圈养动物来获得食物来源,为了抵抗怪物,他需要挖矿获得铁锭,金锭,甚至钻石来制作更高级的武器装备,通常,他还需要对武器装备附魔,来提升效果,为此,他不得不需要经常下矿。在经历了枯燥又乏味的矿工生活后,Steve 打算建造一个水池来放松放松,他打算把水池建造成一个高度为1,长宽分别为N,M的水池,为此,他需要向水池中倒水,但Steve 只有一个水桶,他不想要浪费更多的铁锭来制作更多的水桶,为此,他需要尽可能少的往水池里倒水以尽快建造好水池,但是Steve 的世界有一个很奇怪的特性,每向一个区域倒水的时候,在这个区域会形成一个水源,当一个区域四个方向中至少有两个方向紧挨着这个区域的地方都为水源的话,这个区域也将会形成水源,Steve 想要知道最少他需要倒多少次水才能使水池每处都形成水源。输入格式输入第1行为一个整数T。(1 ≤ T ≤ 1000)第2行到第T+1行每行为两个整数N,M代表水池的长宽。(1 ≤ N,M ≤ 10^9)输出格式输出为T行,每行输出一个整数,代表Steve 最少需要的倒水次数。12345678910111213样例input11 1output1input21 33 3output23题解规律题:规律为(n+m)/2code:123456789101112131415161718#include<bits/stdc++.h>using namespace std;int main(){ int n, m; int t; scanf("%d",&t); while(t --) { scanf("%d %d",&n, &m); int ans = ceil(1.0 * (n + m) / 2); printf("%d\n",ans); } return 0;}掷骰子Description:骰子,中国传统民间娱乐用来投掷的博具,早在战国时期就已经被发明。现在给你 n 个骰子,求 n 个骰子掷出点数之和为 a 的概率是多少。输入格式第一行输入一个整数 T,表示有 T 组测试数据(1≤T≤10)每组测试数据输入两个整数n,a,表示共有n个骰子,骰子点数总和为a(1≤n≤1000,n≤a≤6∗n)输出格式如题。答案对 109+7 取余。12345678样例input21 22 2output16666666827777778题解dp[i][j]表示投掷玩i个骰子和为j的方案书,dp[i][j]=求和(dp[i-1][j-k]),k为第i个骰子的点数。暴力转移即可code:1234567891011121314151617181920212223242526272829303132333435363738394041#include<bits/stdc++.h>using namespace std;#define pii pair<int,int>#define ll long longconst ll mod=1000000007;const int maxn=1000+10;ll dp[maxn][maxn*6];ll quickpow(ll a,ll b){ ll res=1; while(b){ if(b&1) res=res*a%mod; a=a*a%mod; b>>=1; } return res;}void solve(){ int t; int n,a; scanf("%d",&t); while(t--){ memset(dp,0,sizeof(dp)); scanf("%d %d",&n,&a); dp[0][0]=1; for(int i=1;i<=n;i++){ for(int j=i;j<=6*n;j++){ for(int k=j-6;k<j;k++){ if(k<0) continue; dp[i][j]=(dp[i][j]+dp[i-1][k])%mod; } } } printf("%lld\n",dp[n][a]*quickpow(quickpow(6,n),mod-2)%mod); }}int main(){ solve(); return 0;}SubsequenceDescription:Steve 和 Alex 喜欢研究字符串,今天他们学到了一个新名词—“Subsequence“。对于字符串 s 和 t 来说,t 被称为 s 的”Subsequence“当且仅当 s 删除若干字母后能得到 t (也可以不删)。例如:”ab”,”ac”,”bc”都是”abc”的”Subsequence“,而”ba”和”ca”则不是。现在 Steve 和 Alex 手中各自有一个只由小写字母组成的字符串 s 和 t ,请判断 t 是否是 s 的”Subsequence“。输入格式第一行输入一个T,代表数据组数。接下来输入T组,每组包含两行,第一行输入s,第二行输入t。(1≤T≤1000,1≤|t|≤|s|≤10000)输出格式输出T行,如果t是s的”Subsequence“,输入”YES”,否则输出”NO”。12345678910111213样例input3abcacabcbaabcaoutputYESNOYES题解设置一个指针j,如果s1i = s2j,j往后移,判断到最后j是否为m即可,m为t的长度code:123456789101112131415161718192021222324#include<bits/stdc++.h>using namespace std;typedef long long ll;int main(){ int t; cin >> t; while(t --) { string s1, s2; cin >> s1 >> s2; int n = s1.size(); int m = s2.size(); int i = 0, j = 0; while(i < n && j < m) { if(s1[i] == s2[j]) j ++; i ++; } if(j == m) cout << "YES" << '\n'; else cout << "NO" << '\n'; } return 0;}Steve的游戏名Description:定义一个字符串s是一步字符串,当 s 满足以下两个条件:s 中仅包含小写字母。对于任意的1≤i<|s|满足,s[i]+1=s[i+1],也就是说,s[i]在英文字母表中的位置的下一位是s[i+1],特别的,我们认为z的下一位是a,其中|s|表示s的长度。举个例子:abc、zab 都是一步字符串,而 acd、zbc不是。Steve 特别喜欢长长的名字,因此他在 Minecraft 中的名字特别特别的长。Alex 对 Steve 的名字特别感兴趣,她想知道 Steve 的名字中有多少个子串是一步字符串。形式化来说,对于一个字符串 s,问有多少对 <i,j> 满足 1≤i≤j≤n,且 s[i]…s[j] 是一步字符串。保证 Steve 在 Minecraft 中的名字仅包含小写英文字母。输入格式输入包含多组测试数据。第一行一个数字 T ,表示测试数据个数。接下来每两行表示一个测试数据。第一行一个数字 n 。第二行一个长度为 n 的字符串 s。数据范围:1≤T≤100,1≤n≤2⋅105输出格式一个数字表示答案。12345678910样例input23abc3zaboutput66题意O(|s|)的遍历即可,遇到不满足条件的更新最新的满足条件的最大区间|l,r|,答案加上(r-l+1)*(r-l)/2code:1234567891011121314151617181920212223242526272829#include<bits/stdc++.h>using namespace std;typedef long long ll;int main(){ ll t, n; string str; scanf("%d",&t); while(t --) { scanf("%d",&n); cin >> str; ll x = 1, ans = 0; for(int i = 0; i < n - 1; i ++) { if((str[i] - 'a' + 1) % 26 == (str[i + 1] - 'a') % 26) x ++; else { ans += (1 + x) * x / 2 - x; x = 1; } } if(x) ans += (1 + x) * x / 2 - x; ans += n; cout << ans << '\n'; } return 0;}数字串Description:给你一个长度为 n 的数字串,找出其中位数不超过15位的不包含前导0和后导0的数 x ,使得 x+f(x) 是一个回文数,其中 f(x) 表示将 x 反转过来的数。输入格式多组输入,处理到文件结束,样例保证不超过1000组。每组第一行一个整数 n ,表示数字串的长度(1≤n≤1000),接下来一行输入一个长度为 n 的数字串。输出格式第一行一个数 m 表示数字串中符合条件的数的个数(数可以重复)。第二行从小到大输出 m 个数,每个数字之间以空格隔开。1234567891011121314样例input3123output61 2 3 12 23 123提示1+1=2,2+2=4,3+3=6,12+21=33,23+32=55,123+321=444暴力即可过code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546#include<bits/stdc++.h>using namespace std;#define pii pair<int,int>#define ll long longconst ll mod=1000000007;const int maxn=1000000+10;char s[maxn];ll a[maxn];ll fan(ll x){ ll res=0; while(x){ res=res*10+x%10; x/=10; } return res;}void solve(){ ll n; while(~scanf("%lld",&n)){ scanf("%s",s); ll sum=0; for(int i=0;i<n;i++){ if(s[i]=='0') continue; ll x=0; for(int j=0;j<15 && i+j<n;j++){ x=x*10+s[i+j]-'0'; if(s[i+j]=='0') continue; if(x+fan(x)==fan(x+fan(x))){ a[sum++]=x; } } } sort(a,a+sum); printf("%lld\n",sum); for(int i=0;i<sum;i++) printf("%lld ",a[i]); printf("\n"); }}int main(){ solve(); return 0;}Alex的午饭Description:Steve和Alex每天都在为午饭吃什么而发愁,因为吃的东西实在是太多了,而且很多都特别好吃。为了解决吃什么的问题,Alex决定每次吃饭前发布一个问卷调查,让他的好朋友选出他们今天最想吃的食物,然后Alex会根据问卷的结果来确定吃什么每个问卷只收集一种食物,每个食物都由一个数字num来表示。Alex会选出问卷中出现次数超过问卷总数一半的数字来决定今天的午饭输入格式单组输入,每组两行第一行有一个整数N (1≤N≤2×10^7)第二行有N个整数num (num≤10^18),代表每个问卷中的数字输出格式输出一个整数,即出现次数超过N/2的数1234567891011样例input41 1 1 2output1input52 2 3 3 3output3ps:用map做的话会超时好像是什么xx摩尔算法吧code:1234567891011121314151617181920212223#include<bits/stdc++.h>using namespace std;typedef long long ll;int main(){ int t; ll x, ans; int res = 0; scanf("%lld",&t); int i; for(i = 0; i < t; i ++) { scanf("%lld",&x); if(!res) ans = x; if(x == ans) res ++; if(x != ans) res --; } printf("%lld\n",ans); return 0;}The war landDescription:Steve 和 Alex 开始玩一款叫做战争大陆的游戏,整个地图由 n 个岛屿和 n−1 条桥梁组成,第 i 个岛屿的战略能力为 wi ,整个地图是联通的。游戏开始 Steve 和 Alex 需要断掉一座桥梁,这样整个地图就被划分为了两个联通的区域 A 和 B 并且 A 和 B 之间无法到达。为了使游戏尽可能公平,现在他们想让 A 和 B 的战略能力之和的差值的绝对值最小。输入格式第一行输入T代表数据组数。接下来T组,对于每一组:第一行输入n,接下来n−1行,每行输入两个数字u,v代表u和v之间的岛屿有一座桥梁,最后一行输入n个数,第i个数代表第i个岛屿的战略值wi。(1≤T≤10,1≤n≤100000,1≤wi≤10^9,1≤u,v≤n)输出格式输出T组,对于每组输入,输出最小的差值的绝对值。1234567891011121314样例input241 22 32 42 5 7 321 21 2output31题意这是一棵树,我们以1为根节点DFS统计以i为根的子树的大小,然后切一条边其实就是割掉一个子树,处理之后枚举即可。复杂度O(T·n)code:1234567891011121314151617181920212223242526272829303132333435363738#include<bits/stdc++.h>using namespace std;const int N = 200001;long long siz[N],w[N];vector<int> G[N];void dfs(int u,int par){ siz[u]=w[u]; for(int v:G[u]){ if(v==par) continue; dfs(v,u); siz[u]+=siz[v]; }}int main(){ int T; cin>>T; while(T--){ memset(siz,0,sizeof(siz)); int n;cin>>n; for(int i=1;i<=n;i++) G[i].clear(); int u,v; for(int i=1;i<=n-1;i++){ cin>>u>>v; G[u].push_back(v); G[v].push_back(u); } for(int i=1;i<=n;i++) cin>>w[i]; dfs(1,0); long long ans=999999999999999999; for(int i=2;i<=n;i++){ ans=min(ans,abs(siz[1]-2*siz[i])); } cout<<ans<<endl; } return 0;}Number throryDescription:steve 学完了快速幂,现在会他快速的计算:(i^j)%d , Alex 作为一个数学大师,给了 steve 一个问题:已知i∈[1,n],j∈[1,m] ,计算满足 (i^j)%d=0 的 (i,j) 的对数。输入格式T组输入,对于每一组输入三个数n,m,d。(1≤T≤1000,1≤n,m,d≤10^9)。输出格式对于每组输入,输出答案,每个答案占一行。123456789101112样例input43 10 73 5 310 30 6100 100 8output05304937题解code:1234567891011121314151617181920212223242526272829303132333435363738394041424344#include<bits/stdc++.h>using namespace std;typedef long long ll;ll qpow(ll a,ll b){ ll ans=1; while(b){ if(b&1) ans=(ans*a); a=(a*a); b>>=1; } return ans;}int main(){ int T; scanf("%d",&T); while(T--){ ll n,m,d; scanf("%lld %lld %lld",&n,&m,&d); vector<pair<ll,ll> > prs; for(ll i=2;i*i<=d;i++){ if(d%i==0){ long long cnt=0; while(d%i==0){ d/=i;cnt++; } prs.push_back({i,cnt}); } } ll res=0; if(d!=1) prs.push_back({d,1}); for(ll j=1;j<=min(m,1LL*30);j++){ ll g=1; for(auto v:prs){ g*=qpow(v.first,(v.second+j-1)/j); } if(j==30) res+=(m-29)*(n/g); else res+=n/g; } printf("%lld\n",res); } return 0;}Steve的难题Description:Steve参加了2019年的暑期集训,在集训最后一场积分赛时,Steve英勇AC,提交了几十发全A了。Steve顿时惊叹,这不都是水题吗,于是接下来碰到的问题却难倒了他。求1n! 模p意义下的值。输入格式多组输入,处理到文件结束。每行输入两个数n,p,(1≤n≤10^5,n<p≤10^9).数据保证 p 是个质数。输出格式如题123456789样例input3 53 73 11output162题解求解逆元裸题,可以用exgcd(扩展gcd),也可以用费马小定理,由于p为质数,因此x的逆元为x^(p-2)%pcode:1234567891011121314151617181920212223242526272829303132#include<bits/stdc++.h>using namespace std;typedef long long ll;ll quick_pow(ll a, ll b, ll p){ ll res = 1; if(b <= 0) return res; while(b) { if(b & 1) res = res * a % p; b >>= 1; a = a * a % p; } return res;}//x 的逆元为 x^(p - 2) % p;int main(){ ll n, p; while(~scanf("%lld %lld", &n, &p)) { ll res = 1; for(ll i = 1; i <= n; i ++) { res = res * quick_pow(i, p - 2, p) % p; } printf("%lld\n", res); } return 0;}Steve’s Shortest PathDescription:Alex 和 Steve 来到了一个神奇的国度,这个国家有 n 个城市和 m 条道路。这 m 条道路都是双向的,而且这个国家的客车有个特点,每辆客车除出发城市和到达城市外有且仅可经过一个城市。假设u城市到v有一条道路并且 v 到 p 有一条道路,那么客车从 u 出发不能到达 v 但是能到达 p,Steve 和 Alex 在编号为 1 的城市,他们想知道能不能到达编号为 n 的城市,如果能,最少需要坐几次客车?输入格式单组输入。第一行输入 n 和 m 代表城市的个数和路径的条数。接下来 m 行每行输入两个数 u 和 v 代表 u 到 v 之间有条路。(2≤n,m≤10^6,1≤u,v≤n)。输出格式如果 Steve 和 Alex 能够到达终点,输出最少需要坐几次车才能到达,否则输出−1。123456789101112样例input2 11 2output-1input3 21 22 3output1题解直接BFS/Dijkstra即可,记录两个状态分别代表到达i点最短路为奇偶的情况.即dis[i][0]代表到i点走了偶数步的最短路,dis[i][1]代表到i点走了奇数步的最短路,然后答案即为dis[i][0]/2code:12345678910111213141516171819202122232425262728293031323334353637383940414243#include<bits/stdc++.h>using namespace std;const int maxn=1000000+10;vector<int>vec[maxn];int step[maxn];bool vis[maxn];int n,m;void bfs(int x){ queue<int>que; que.push(x); vis[x]=1; step[x]=0; while(!que.empty()){ x=que.front(); que.pop(); for(int i=0;i<vec[x].size();i++){ int y=vec[x][i]; for(int j=0;j<vec[y].size();j++){ int z=vec[y][j]; if(vis[z]) continue; vis[z]=1; step[z]=step[x]+1; que.push(z); if(z==n) return ; } } }}int main(){ scanf("%d %d",&n,&m); int u,v; for(int i=0;i<m;i++){ scanf("%d %d",&u,&v); vec[u].push_back(v); vec[v].push_back(u); } bfs(1); if(step[n]==0) printf("-1\n"); else printf("%d\n",step[n]); return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day27]]></title>
<url>%2F2019%2F08%2F16%2FDay27%2F</url>
<content type="text"><![CDATA[Day27今天讲的是 KPM + hash算法好好学习!!!OJPS:这次的题基本上都是用KMP写的,hash算法的写法等理解好了再补KMP算法解释详情注意一下链接前后缀数组的理解KMP解释KMP白话讲解KMP生动一点的讲解贴一个板子123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475#include<bits/stdc++.h>using namespace std;string s,t;int n,m;vector<int> cal_nxt(string s){ int n=(int)s.length(); vector<int> nxt(n); for(int i=1;i<n;i++){ int j=nxt[i-1]; while(s[i]!=s[j]&&j>0) j=nxt[j-1]; if(s[i]==s[j]) j++; nxt[i]=j; } return nxt;}int main(){ cin>>s>>t; m=t.length(); n=s.length(); string T=t+'#'+s; vector<int> nxt=cal_nxt(T); for(int i=m+1;i<(int)T.length();i++){ if(nxt[i]==m){ cout<<"YES"<<endl;return 0; } } cout<<"NO"<<endl; return 0;}//另一个板子string start,en;int n, m;int nxt[1000010];//得到nxt维护数组void getnxt(){ int j, k; j = 0, k = -1, nxt[0] = -1; while(j < m) { //从头比或相等则比较下去并记录最长公共真前、后缀长度 if(k == -1 || en[j] == en[k]) { //j之前的最长公共真前、后缀长度为k,前缀下标0~k-1,后缀下标j-k~j-1 nxt[++ j] = ++ k; } else k = nxt[k];//k回退到Next[k]的位置 }}int kmp(){ getnxt(); int ans = 0; int j, k; j = 0, k = 0; while(j < n) { //k==-1相当于从start的开始(重新)比较,相等就比下去 if(k == -1 || en[k] == start[j]) { ++ j; ++ k; } else k = nxt[k]; if(k == m) { k = nxt[k];//把j位置的字符和k位置的字符对齐,便于下次比较 ans ++; } } return ans;}hash算法解释详情注意一下链接解释加一个板子123456789101112131415161718192021222324252627282930313233343536#include<bits/stdc++.h>using namespace std;typedef unsigned long long ull;const ull base = 2333;const ull mod = 1e9+9;const int N = 1e6+100;ull hashes[N],p[N];ull gethashes(int l,int r){ return (hashes[r]%mod-(hashes[l-1]%mod*p[r-l+1]%mod)%mod+mod)%mod;}char s[N],t[N];int main(){ int T; scanf("%d",&T); while(T--){ scanf("%s %s",t+1,s+1); int n=strlen(s+1); int m=strlen(t+1); p[0]=1; for(int i=1;i<=n;i++){ hashes[i]=(hashes[i-1]*base%mod+s[i]%mod)%mod; p[i]=(p[i-1]%mod*base%mod)%mod; } ull ans=0; for(int i=1;i<=m;i++) ans=(ans*base%mod+t[i]%mod)%mod; int res=0; for(int i=m;i<=n;i++){ if(gethashes(i-m+1,i)==ans){ res++; } } printf("%d\n",res); } return 0;}Number SequenceDescription:Given two sequences of numbers : a[1], a[2], …… , a[N], and b[1], b[2], …… , b[M] (1 <= M <= 10000, 1 <= N <= 1000000). Your task is to find a number K which make a[K] = b[1], a[K + 1] = b[2], …… , a[K + M - 1] = b[M]. If there are more than one K exist, output the smallest one.InputThe first line of input is a number T which indicate the number of cases. Each case contains three lines. The first line is two numbers N and M (1 <= M <= 10000, 1 <= N <= 1000000). The second line contains N integers which indicate a[1], a[2], …… , a[N]. The third line contains M integers which indicate b[1], b[2], …… , b[M]. All integers are in the range of [-1000000, 1000000].OutputFor each test case, you should output one line which only contain K described above. If no such K exists, output -1 instead.1234567891011Sample Input213 51 2 1 2 3 1 2 3 1 3 2 1 21 2 3 1 313 51 2 1 2 3 1 2 3 1 3 2 1 21 2 3 2 1Sample Output6-1code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061#include<bits/stdc++.h>using namespace std;const int maxx = 1e6 + 10;int n, m;int a[maxx], b[maxx];int nxt[maxx];void getnxt(){ int j = 0, k = -1; nxt[0] = -1; while(j < m) { if(k == -1 || b[k] == b[j]) { nxt[++ j] = ++ k; } else k = nxt[k]; }}int kpm(){ getnxt(); int j = 0, k = 0; int res = -1; while(j < n) { if(k == -1 || b[k] == a[j]) { ++ j; ++ k; } else k = nxt[k]; if(k == m) { res = j; break; } } if(res == -1) return -1; else return res - m + 1;}int main(){ ios::sync_with_stdio(false); int t; cin >> t; while(t --) { cin >> n >> m; for(int i = 0; i < n; i ++) cin >> a[i]; for(int i = 0; i < m; i ++) cin >> b[i]; cout << kpm() << '\n'; } return 0;}OulipoDescription:The French author Georges Perec (1936–1982) once wrote a book, La disparition, without the letter ‘e’. He was a member of the Oulipo group. A quote from the book:Tout avait Pair normal, mais tout s’affirmait faux. Tout avait Fair normal, d’abord, puis surgissait l’inhumain, l’affolant. Il aurait voulu savoir où s’articulait l’association qui l’unissait au roman : stir son tapis, assaillant à tout instant son imagination, l’intuition d’un tabou, la vision d’un mal obscur, d’un quoi vacant, d’un non-dit : la vision, l’avision d’un oubli commandant tout, où s’abolissait la raison : tout avait l’air normal mais…Perec would probably have scored high (or rather, low) in the following contest. People are asked to write a perhaps even meaningful text on some subject with as few occurrences of a given “word” as possible. Our task is to provide the jury with a program that counts these occurrences, in order to obtain a ranking of the competitors. These competitors often write very long texts with nonsense meaning; a sequence of 500,000 consecutive ‘T’s is not unusual. And they never use spaces.So we want to quickly find out how often a word, i.e., a given string, occurs in a text. More formally: given the alphabet {‘A’, ‘B’, ‘C’, …, ‘Z’} and two finite strings over that alphabet, a word W and a text T, count the number of occurrences of W in T. All the consecutive characters of W must exactly match consecutive characters of T. Occurrences may overlap.InputThe first line of the input file contains a single number: the number of test cases to follow. Each test case has the following format:One line with the word W, a string over {‘A’, ‘B’, ‘C’, …, ‘Z’}, with 1 ≤ |W| ≤ 10,000 (here |W| denotes the length of the string W).One line with the text T, a string over {‘A’, ‘B’, ‘C’, …, ‘Z’}, with |W| ≤ |T| ≤ 1,000,000.OutputFor every test case in the input file, the output should contain a single number, on a single line: the number of occurrences of the word W in the text T.123456789101112Sample Input3BAPCBAPCAZAAZAZAZAVERDIAVERDXIVYERDIANSample Output130code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162#include<iostream>using namespace std;string start,en;int n, m;int nxt[1000010];//得到nxt维护数组void getnxt(){ int j, k; j = 0, k = -1, nxt[0] = -1; while(j < m) { //从头比或相等则比较下去并记录最长公共真前、后缀长度 if(k == -1 || en[j] == en[k]) { //j之前的最长公共真前、后缀长度为k,前缀下标0~k-1,后缀下标j-k~j-1 nxt[++ j] = ++ k; } else k = nxt[k];//k回退到Next[k]的位置 }}int kmp(){ getnxt(); int ans = 0; int j, k; j = 0, k = 0; while(j < n) { //k==-1相当于从start的开始(重新)比较,相等就比下去 if(k == -1 || en[k] == start[j]) { ++ j; ++ k; } else k = nxt[k]; if(k == m) { k = nxt[k];//把j位置的字符和k位置的字符对齐,便于下次比较 ans ++; } } return ans;}int main(){ ios::sync_with_stdio(false); int t; cin >> t; while(t --) { cin >> en >> start; n = start.size(); m = en.size(); cout << kmp() << '\n'; } return 0;}剪花布条Description:一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案。对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢?Input输入中含有一些数据,分别是成对出现的花布条和小饰条,其布条都是用可见ASCII字符表示的,可见的ASCII字符有多少个,布条的花纹也有多少种花样。花纹条和小饰条不会超过1000个字符长。如果遇见#字符,则不再进行工作。Output输出能从花纹布中剪出的最多小饰条个数,如果一块都没有,那就老老实实输出0,每个结果之间应换行。1234567Sample Inputabcde a3aaaaaa aa#Sample Output03code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061#include<iostream>using namespace std;string start,en;int n, m;int nxt[10010];//得到nxt维护数组void getnxt(){ int j, k; j = 0, k = -1, nxt[0] = -1; while(j < m) { //从头比或相等则比较下去并记录最长公共真前、后缀长度 if(k == -1 || en[j] == en[k]) { //j之前的最长公共真前、后缀长度为k,前缀下标0~k-1,后缀下标j-k~j-1 nxt[++ j] = ++ k; } else k = nxt[k];//k回退到Next[k]的位置 }}int kmp(){ getnxt(); int ans = 0; int j, k; j = 0, k = 0; while(j < n) { //k==-1相当于从start的开始(重新)比较,相等就比下去 if(k == -1 || en[k] == start[j]) { ++ j; ++ k; } else k = nxt[k]; if(k == m) { k = 0; ans ++; } } return ans;}int main(){ ios::sync_with_stdio(false); while(cin >> start) { if(start == "#") break; cin >> en; n = start.size(); m = en.size(); cout << kmp() << '\n'; } return 0;}Cyclic NacklaceDescription:CC always becomes very depressed at the end of this month, he has checked his credit card yesterday, without any surprise, there are only 99.9 yuan left. he is too distressed and thinking about how to tide over the last days. Being inspired by the entrepreneurial spirit of “HDU CakeMan”, he wants to sell some little things to make money. Of course, this is not an easy task.As Christmas is around the corner, Boys are busy in choosing christmas presents to send to their girlfriends. It is believed that chain bracelet is a good choice. However, Things are not always so simple, as is known to everyone, girl’s fond of the colorful decoration to make bracelet appears vivid and lively, meanwhile they want to display their mature side as college students. after CC understands the girls demands, he intends to sell the chain bracelet called CharmBracelet. The CharmBracelet is made up with colorful pearls to show girls’ lively, and the most important thing is that it must be connected by a cyclic chain which means the color of pearls are cyclic connected from the left to right. And the cyclic count must be more than one. If you connect the leftmost pearl and the rightmost pearl of such chain, you can make a CharmBracelet. Just like the pictrue below, this CharmBracelet’s cycle is 9 and its cyclic count is 2:Now CC has brought in some ordinary bracelet chains, he wants to buy minimum number of pearls to make CharmBracelets so that he can save more money. but when remaking the bracelet, he can only add color pearls to the left end and right end of the chain, that is to say, adding to the middle is forbidden.CC is satisfied with his ideas and ask you for help.InputThe first line of the input is a single integer T ( 0 < T <= 100 ) which means the number of test cases.Each test case contains only one line describe the original ordinary chain to be remade. Each character in the string stands for one pearl and there are 26 kinds of pearls being described by ‘a’ ~’z’ characters. The length of the string Len: ( 3 <= Len <= 100000 ).OutputFor each case, you are required to output the minimum count of pearls added to make a CharmBracelet.123456789Sample Input3aaaabcaabcdeSample Output025code:123456789101112131415161718192021222324252627282930313233343536373839#include<bits/stdc++.h>using namespace std;typedef long long ll;int n;string str;int nxt[1000010];void kmp(){ int j = 0, k = -1; nxt[0] = -1; while(j < n) { if(k == -1 || str[k] == str[j]) { nxt[++ j] = ++ k; } else k = nxt[k]; }}int main(){ ios::sync_with_stdio(false); ll t; cin >> t; while(t --) { cin >> str; n = str.size(); kmp(); //n - nxt[n]为最小循环长度 if(nxt[n] && n % (n - nxt[n]) == 0) printf("0\n"); //一个循环节的长度减去多余的长度,就是需要补的长度。 else printf("%d\n",n - nxt[n] - n % (n - nxt[n])); } return 0;}PeriodDescription:For each prefix of a given string S with N characters (each character has an ASCII code between 97 and 126, inclusive), we want to know whether the prefix is a periodic string. That is, for each i (2 <= i <= N) we want to know the largest K > 1 (if there is one) such that the prefix of S with length i can be written as A K ,that is A concatenated K times, for some string A. Of course, we also want to know the period K.InputThe input consists of several test cases. Each test case consists of two lines. The first one contains N (2 <= N <= 1 000 000) – the size of the string S.The second line contains the string S. The input file ends with a line, having thenumber zero on it.OutputFor each test case, output “Test case #” and the consecutive test case number on a single line; then, for each prefix with length i that has a period K > 1, output the prefix size i and the period K separated by a single space; the prefix sizes must be in increasing order. Print a blank line after each test case.12345678910111213141516Sample Input3aaa12aabaabaabaab0Sample OutputTest case #12 23 3Test case #22 26 29 312 4code:1234567891011121314151617181920212223242526272829303132333435363738394041424344#include<iostream>#include<cstring>#include<cstdio>#include<string>#include<algorithm>using namespace std;#define N 1000010char s[N];int nextval[N];int len;void getnext(const char *s){ int i = 0, j = -1; nextval[0] = -1; while(i != len) { if(j == -1 || s[i] == s[j]) nextval[++i] = ++j; else j = nextval[j]; }}int main(){ int T = 1; int length, add; while(scanf("%d", &len) && len) { scanf("%s", s); getnext(s); printf("Test case #%d\n", T++); for(int i = 1; i <= len; ++i) { length = i - nextval[i]; //循环节的长度 if(i != length && i % length == 0) //如果有多个循环 printf("%d %d\n", i, i / length); } printf("\n"); } return 0;}Power StringsDescription:Given two strings a and b we define ab to be their concatenation. For example, if a = “abc” and b = “def” then ab = “abcdef”. If we think of concatenation as multiplication, exponentiation by a non-negative integer is defined in the normal way: a^0 = “” (the empty string) and a^(n+1) = a*(a^n).InputEach test case is a line of input representing s, a string of printable characters. The length of s will be at least 1 and will not exceed 1 million characters. A line containing a period follows the last test case.OutputFor each s you should print the largest n such that s = a^n for some string a.1234567891011Sample Inputabcdaaaaababab.Sample Output143HintThis problem has huge input, use scanf instead of cin to avoid time limit exceed.code:123456789101112131415161718192021222324252627282930313233343536#include<iostream>#include<stdio.h>using namespace std;int n;int nxt[1000010];string str;void getnxt(){ int j = 0, k = -1; nxt[0] = -1; while(j < n) { if(k == -1 || str[j] == str[k]) { nxt[++ j] = ++ k; } else k = nxt[k]; }}int main(){ ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); while(cin >> str) { if(str == ".") break; n = str.size(); getnxt(); int len = n - nxt[n]; if(n % len == 0) printf("%d\n",n / len); else printf("1\n"); } return 0;}Seek the Name, Seek the FameDescription:The little cat is so famous, that many couples tramp over hill and dale to Byteland, and asked the little cat to give names to their newly-born babies. They seek the name, and at the same time seek the fame. In order to escape from such boring job, the innovative little cat works out an easy but fantastic algorithm:Step1. Connect the father’s name and the mother’s name, to a new string S.Step2. Find a proper prefix-suffix string of S (which is not only the prefix, but also the suffix of S).Example: Father=’ala’, Mother=’la’, we have S = ‘ala’+’la’ = ‘alala’. Potential prefix-suffix strings of S are {‘a’, ‘ala’, ‘alala’}. Given the string S, could you help the little cat to write a program to calculate the length of possible prefix-suffix strings of S? (He might thank you by giving your baby a name:)InputThe input contains a number of test cases. Each test case occupies a single line that contains the string S described above.Restrictions: Only lowercase letters may appear in the input. 1 <= Length of S <= 400000.OutputFor each test case, output a single line with integer numbers in increasing order, denoting the possible length of the new baby’s name.123456Sample InputababcababababcababaaaaaSample Output2 4 9 181 2 3 4 5code:123456789101112131415161718192021222324252627282930#include<stdio.h>#include<string.h>using namespace std;const int N = 400005;char p[N];int next[N],arr[N];void getNext(char p[],int m,int next[]){ int j=0; int t=-1; next[0]=-1; while(j<m){ if(t<0||p[j]==p[t]){ next[++j]=++t; } else t=next[t]; }}int main(){ while(scanf("%s",p)!=EOF){ int m=strlen(p); getNext(p,m,next); int cnt=0; for(int i=m;next[i]!=-1;i=next[i]) arr[cnt++]=i; for(int i=cnt-1;i>0;i--) printf("%d ",arr[i]); printf("%d\n",arr[0]); } return 0;}Compress WordsDescription:Amugae has a sentence consisting of n words. He want to compress this sentence into one word. Amugae doesn’t like repetitions, so when he merges two words into one word, he removes the longest prefix of the second word that coincides with a suffix of the first word. For example, he merges “sample” and “please” into “samplease”.Amugae will merge his sentence left to right (i.e. first merge the first two words, then merge the result with the third word and so on). Write a program that prints the compressed word after the merging process ends.InputThe first line contains an integer n (1≤n≤105), the number of the words in Amugae’s sentence.The second line contains n words separated by single space. Each words is non-empty and consists of uppercase and lowercase English letters and digits (‘A’, ‘B’, …, ‘Z’, ‘a’, ‘b’, …, ‘z’, ‘0’, ‘1’, …, ‘9’). The total length of the words does not exceed 106.OutputIn the only line output the compressed word after the merging process ends as described in the problem.题解KMP模板题,用第二个串与第一个串中等长后缀进行匹配即可,比如第一个串长度为n,第二个串长度为m,n>m,则从第一个串的n-m处开始与第二个串匹配,最大匹配长度即为可以合并的长度。1234567891011ExamplesInput5I want to order pizzaOutputIwantorderpizzaInput5sample please ease in outOutputsampleaseinoutcode:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>#include <cmath>#include <vector>#include <queue>#include <string.h>using namespace std;const int maxn = 1e6 + 10;int nxt[maxn];char str[maxn];char ans[maxn];int lenn,lenm;void get_next(){ int k = -1, j = 0; nxt[0] = -1; while(j < lenm){ if(k == -1 || str[j] == str[k]) nxt[++j] = ++k; else k = nxt[k]; }}//返回最长匹配长度int KMP(int pos) { get_next(); int j = 0; for (int i = pos; i < lenn; i++) { while (j&&ans[i] != str[j])j = nxt[j]; if (ans[i] == str[j])j++; if (j == lenm) { return lenm; } } return j;}signed main() { int N; scanf("%d",&N); scanf("%s",ans); int pos=0; lenn=strlen(ans); for (int i = 2; i <= N; i++) { scanf("%s",str); lenm=strlen(str); int now=KMP(max(pos-lenm,0)); for(int j=now;j<lenm;j++){ ans[lenn++]=str[j]; } pos=lenn; } for(int i=0;i<lenn;i++){ printf("%c",ans[i]); } puts(""); return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>数论</tag>
<tag>KPM</tag>
<tag>hash算法</tag>
<tag>匹配字符串算法</tag>
</tags>
</entry>
<entry>
<title><![CDATA[JAVA实现大数相加]]></title>
<url>%2F2019%2F08%2F16%2FJAVA%E5%AE%9E%E7%8E%B0%E5%A4%A7%E6%95%B0%E7%9B%B8%E5%8A%A0%2F</url>
<content type="text"><![CDATA[Day27今天无意间看到了,就记录下来吧,等有时间了再补上好好学习!!!简单的介绍一下JavaJava的大数相加:先导入包(和python有点点像)123import java.*;import java.util.*;import java.math.*;*就不用解释了吧(就是通配符,写一个*的话表示可以用到这个包下面)介绍一下常用的包所用到的包名说明java.lang该包提供了Java编程的基础类,例如 Object、Math、String、StringBuffer、System、Thread等,不使用该包就很难编写Java代码了。java.util该包提供了包含集合框架、遗留的集合类、事件模型、日期和时间实施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。java.io该包通过文件系统、数据流和序列化提供系统的输入与输出。java.net该包提供实现网络应用与开发的类。java.sql该包提供了使用Java语言访问并处理存储在数据源(通常是一个关系型数据库)中的数据API。java.awt这两个包提供了GUI设计与开发的类。java.awt包提供了创建界面和绘制图形图像的所有类,而javax.swing包提供了一组“轻量级”的组件,尽量让这些组件在所有平台上的工作方式相同。java.swingjava.text提供了与自然语言无关的方式来处理文本、日期、数字和消息的类和接口。详情链接java.lang 详解java.util 详解java.io 详解java.net 详解java.sql 详解java.awt 详解javax.swing 详解java.text 详解书写格式主要入口为public static void main(String[] args){}其中String[] args也可以写成String args[],但还是推荐写第一种框架123456789public class Text(自己命名){ public static void main(String[] args) { }}特别注意!!Java中十分敏感大小写!!!每一个单词的开头字母都要大写Eg:First FirstAppleJAVA实现大数相加模板对应题目HDU100212345678910111213141516171819202122232425import java.math.*;import java.util.*;import java.*;//注意一下,在OJ上交JAVA题的时候要把`自己命名`改成Main不然不给过编译public class Main{ public static void main(String[] args) { Scanner cin = new Scanner(System.in); int t = cin.nextInt(); int num = 1; int x=0; while(t>0) { if(x!=0) System.out.println(""); else x=1; BigInteger a = cin.nextBigInteger(); BigInteger b = cin.nextBigInteger(); System.out.println("Case "+num+":"); System.out.println(a+" + "+b+" = "+a.add(b)); num++; t--; } }}其他的大数模拟的例子链接(づ ̄3 ̄)づ╭❤~]]></content>
<categories>
<category>JAVA</category>
<category>大数相加</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>JAVA</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day26]]></title>
<url>%2F2019%2F08%2F15%2FDay26%2F</url>
<content type="text"><![CDATA[Day26今天讲的是 容斥定理 + 鸽巢原理好好学习!!!OJ内容讲解传送门Ekka DokkaDescription:Ekka and his friend Dokka decided to buy a cake. They both love cakes and that’s why they want to share the cake after buying it. As the name suggested that Ekka is very fond of odd numbers and Dokka is very fond of even numbers, they want to divide the cake such that Ekka gets a share of N square centimeters and Dokka gets a share of M square centimeters where N is odd and M is even. Both N and M are positive integers.They want to divide the cake such that N * M = W, where W is the dashing factor set by them. Now you know their dashing factor, you have to find whether they can buy the desired cake or not.InputInput starts with an integer T (≤ 10000), denoting the number of test cases.Each case contains an integer W (2 ≤ W < 2^63). And W will not be a power of 2.OutputFor each case, print the case number first. After that print “Impossible” if they can’t buy their desired cake. If they can buy such a cake, you have to print N and M. If there are multiple solutions, then print the result where M is as small as possible.123456789Sample Input310512Sample OutputCase 1: 5 2Case 2: ImpossibleCase 3: 3 4code:1234567891011121314151617181920212223242526#include<bits/stdc++.h>using namespace std;typedef long long ll;int main(){ ll t, w; ll k = 1; scanf("%lld",&t); while(t --) { scanf("%lld",&w); ll x = 1; if(w % 2 == 0) { while(w % 2 == 0) { x *= 2; w /= 2; } printf("Case %lld: %lld %lld\n",k ++, w, x); } else printf("Case %lld: Impossible\n",k ++); } return 0;}How many integers can you findDescription:Now you get a number N, and a M-integers set, you should find out how many integers which are small than N, that they can divided exactly by any integers in the set. For example, N=12, and M-integer set is {2,3}, so there is another set {2,3,4,6,8,9,10}, all the integers of the set can be divided exactly by 2 or 3. As a result, you just output the number 7.InputThere are a lot of cases. For each case, the first line contains two integers N and M. The follow line contains the M integers, and all of them are different from each other. 0<N<2^31,0<M<=10, and the M integer are non-negative and won’t exceed 20.OutputFor each case, output the number.12345Sample Input12 22 3Sample Output7code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546#include<bits/stdc++.h>using namespace std;typedef long long ll;ll gcd(ll a, ll b){ return !b ? a : gcd(b, a % b);}ll lcm(ll a, ll b){ return (a / gcd(a, b) * b);}int a[11];int main(){ ll n, m, cnt; ll sum, cnt1, LCM; while(~scanf("%lld %lld",&n, &m)) { ll x; cnt = 0, sum = 0; for(int i = 0; i < m; i ++) { scanf("%lld",&x); if(x != 0) { a[cnt ++] = x; } } for(int i = 1; i < (1 << cnt); i ++) { cnt1 = 0, LCM = 1; for(int j = 0; j < cnt; j ++) { if(i >> j & 1) { cnt1 ++; LCM = lcm(LCM, a[j]); } } if(cnt1 % 2 == 0) sum -= (n - 1) / LCM; else sum += (n - 1) / LCM; } printf("%lld\n", sum); } return 0;}Co-primeDescription:Given a number N, you are asked to count the number of integers between A and B inclusive which are relatively prime to N.Two integers are said to be co-prime or relatively prime if they have no common positive divisors other than 1 or, equivalently, if their greatest common divisor is 1. The number 1 is relatively prime to every integer.InputThe first line on input contains T (0 < T <= 100) the number of test cases, each of the next T lines contains three integers A, B, N where (1 <= A <= B <= 10^15) and (1 <=N <= 10^9).OutputFor each test case, print the number of integers between A and B inclusive which are relatively prime to N. Follow the output format below.12345678910Sample Input21 10 23 15 5Sample OutputCase #1: 5Case #2: 10HintIn the first test case, the five integers in range [1,10] which are relatively prime to 2 are {1,3,5,7,9}.code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152#include<bits/stdc++.h>using namespace std;typedef long long ll;int aa[10001];int main(){ ll t, a, b, n; ll k = 1; cin >> t; while(t --) { ll cnt = 0; cin >> a >> b >> n; for(int i = 2; i * i <= n; i ++) { if(n % i == 0) aa[++ cnt] = i; while(n % i == 0) n = n / i; } if(n != 1) aa[++ cnt] = n; ll sum = 0; for(int i = 1; i < (1 << cnt); i ++) { ll ans = 0, sum1 = 1; for(int j = 0; j < cnt; j ++) { if(1 & (i >> j)) { sum1 = sum1 * aa[j + 1]; ans ++; } } if(ans & 1) { sum += b / sum1; sum -= (a - 1) / sum1; } else { sum -= b / sum1; sum += (a - 1) / sum1; } } printf("Case #%d: %lld\n", k ++, b - a + 1 - sum); } return 0;}Find a multipleDescription:The input contains N natural (i.e. positive integer) numbers ( N <= 10000 ). Each of that numbers is not greater than 15000. This numbers are not necessarily different (so it may happen that two or more of them will be equal). Your task is to choose a few of given numbers ( 1 <= few <= N ) so that the sum of chosen numbers is multiple for N (i.e. N * k = (sum of chosen numbers) for some natural number k).InputThe first line of the input contains the single number N. Each of next N lines contains one number from the given set.OutputIn case your program decides that the target set of numbers can not be found it should print to the output the single number 0. Otherwise it should print the number of the chosen numbers in the first line followed by the chosen numbers themselves (on a separate line each) in arbitrary order.If there are more than one set of numbers with required properties you should print to the output only one (preferably your favorite) of them.1234567891011Sample Input512341Sample Output223这一题的解不是固定的code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889#include<iostream>#include<string.h>#include<stdio.h>using namespace std;typedef long long ll;const int maxx = 1e5;int a[maxx];int sum[maxx];int main(){ int n; scanf("%d",&n); memset(sum, 0, sizeof sum); for(int i = 1; i <= n; i ++) { scanf("%d",&a[i]); sum[i] = (sum[i - 1] + a[i]) % n; } for(int i = 0; i <= n; i ++) { for(int j = i + 1; j <= n; j ++) { if(sum[i] == sum[j]) { printf("%d\n",j - i); for(int k = i + 1; k <= j; k ++) { cout << a[k] << endl; } return 0; } } } return 0;}//另一种写法#include<iostream>#include<string.h>#include<stdio.h>using namespace std;typedef long long ll;const int maxx = 1e6;int a[maxx];int sum[maxx];int b[maxx];int main(){ int n; while(~scanf("%d",&n)) { memset(sum, 0, sizeof sum); memset(b, 0, sizeof b); for(int i = 1; i <= n; i ++) { scanf("%d",&a[i]); sum[i] = (sum[i - 1] + a[i]) % n; } for(int i = 1; i <= n; i ++) { if(sum[i] == 0) { printf("%d\n",i); for(int j = 1; j <= i; j ++) { if(j != 1) printf(" %d", a[j]); else printf("%d",a[j]); } break; } if(b[sum[i]] == 0) b[sum[i]] = i; else { printf("%d\n",i - b[sum[i]]); for(int j = b[sum[i]] + 1; j <= i; j ++) { if(j != b[sum[i]] + 1) printf(" %d",a[j]); else printf("%d",a[j]); } break; } } } return 0;}吃糖果Description:HOHO,终于从Speakless手上赢走了所有的糖果,是Gardon吃糖果时有个特殊的癖好,就是不喜欢将一样的糖果放在一起吃,喜欢先吃一种,下一次吃另一种,这样;可是Gardon不知道是否存在一种吃糖果的顺序使得他能把所有糖果都吃完?请你写个程序帮忙计算一下。Input第一行有一个整数T,接下来T组数据,每组数据占2行,第一行是一个整数N(0<N<=1000000),第二行是N个数,表示N种糖果的数目Mi(0<Mi<=1000000)。Output对于每组数据,输出一行,包含一个”Yes”或者”No”。123456789101112Sample Input234 1 155 4 3 2 1Sample OutputNoYesPlease use function scanfcode:12345678910111213141516171819202122232425262728#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxx = 1e7 + 10;int a[maxx];ll sum;int main(){ ll t, n; scanf("%lld",&t); while(t --) { sum = 0; scanf("%lld",&n); for(int i = 1; i <= n; i ++) { scanf("%d",&a[i]); sum += a[i]; } sort(a + 1, a + n + 1); if(a[n] <= sum - a[n] + 1) printf("Yes\n"); else printf("No\n"); } return 0;}Teacher BoDescription:Teacher BoBo is a geography teacher in the school.One day in his class,he marked N points in the map,the i-th point is at (Xi,Yi).He wonders,whether there is a tetrad (A,B,C,D)(A<B,C<D,A≠CorB≠D) such that the manhattan distance between A and B is equal to the manhattan distance between C and D.If there exists such tetrad,print “YES”,else print “NO”.InputFirst line, an integer T. There are T test cases.(T≤50)In each test case,the first line contains two intergers, N, M, means the number of points and the range of the coordinates.(N,M≤105).Next N lines, the i-th line shows the coordinate of the i-th point.(Xi,Yi)(0≤Xi,Yi≤M).OutputT lines, each line is “YES” or “NO”.1234567891011121314Sample Input23 101 12 23 34 108 82 33 34 4Sample OutputYESNOcode:123456789101112131415161718192021222324252627282930313233343536373839404142#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxx = 1e5 + 10;map<int, int > mp;struct node{ int x, y;}e[maxx];int main(){ int t, n, m; scanf("%d",&t); while(t --) { for(int i = 1; i <= n; i ++) mp.clear(); scanf("%d %d",&n, &m); for(int i = 1; i <= n; i ++) { scanf("%d %d",&e[i].x, &e[i].y); } int cnt = 0, flag = 0; for(int i = 1; i <= n; i ++) { for(int j = i + 1; j <= n; j ++) { int x = abs(e[i].x - e[j].x) + abs(e[i].y - e[j].y); mp[x] ++; if(mp[x] >= 2) { flag = 1; break; } } if(flag) break; } if(flag) puts("YES"); else puts("NO"); } return 0;}跳蚤Description:Z城市居住着很多只跳蚤。在Z城市周六生活频道有一个娱乐节目。一只跳蚤将被请上一个高空钢丝的正中央。钢丝很长,可以看作是无限长。节目主持人会给该跳蚤发一张卡片。卡片上写有N+1个自然数。其中最后一个是M,而前N个数都不超过M,卡片上允许有相同的数字。跳蚤每次可以从卡片上任意选择一个自然数S,然后向左,或向右跳S个单位长度。而他最终的任务是跳到距离他左边一个单位长度的地方,并捡起位于那里的礼物。比如当N=2,M=18时,持有卡片(10, 15, 18)的跳蚤,就可以完成任务:他可以先向左跳10个单位长度,然后再连向左跳3次,每次15个单位长度,最后再向右连跳3次,每次18个单位长度。而持有卡片(12, 15, 18)的跳蚤,则怎么也不可能跳到距他左边一个单位长度的地方。当确定N和M后,显然一共有M^N张不同的卡片。现在的问题是,在这所有的卡片中,有多少张可以完成任务。Input两个整数N和M(N <= 15 , M <= 100000000)。Output可以完成任务的卡片数。12345678Sample Input2 4Sample Output12Hint这12张卡片分别是:(1, 1, 4), (1, 2, 4), (1, 3, 4), (1, 4, 4), (2, 1, 4), (2, 3, 4),(3, 1, 4), (3, 2, 4), (3, 3, 4), (3, 4, 4), (4, 1, 4), (4, 3, 4)设卡片号为 a1,a2,…,an,m,跳蚤跳到对应号的次数是 x1,x2,…,xn,跳 m 个单位长度的次数是 xn+1那么问题就转化为求:a[1]x1+a[2]x2+…+a[n]xn+mx(n+1)=1,一共有多少种情况而上述公式实质是求:GCD(a1,a2,…,an,m)=1故先对 m 进行素因子分解,求出总的排列组合个数,即有:m^n 种,再根据容斥定理排除公因子非 1 的情况即可设 g 为公因子非 1 的情况数,f(i) 表示有 i 个公因子的情况数,根据奇加偶减,有:g=f(1)-f(2)+f(3)-…f(k)设g为公因子非1的情况数,f(i) 表示有 i 个公因子的情况数,由容斥原理得:g = f(1) - f(2) + f(3) -… f(k)code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071#include<iostream>#include<stdio.h>using namespace std;typedef long long ll;const int maxx = 111;int a[maxx], num;void get_prime(ll n){ num = 0; for(int i = 2; i * i <= n; i ++) { if(n % i == 0) { a[++ num] = i; while(n % i == 0) { n = n / i; } } } if(n > 1) a[++ num] = n;}ll quick_pow(ll a, ll b){ ll res = 1; while(b) { if(b & 1) res = res * a; b >>= 1; a = a * a; } return res;}ll temp, ans;int aa[110], n, m;void dfs(int b, int cnt, int c){ if(cnt == c) { int x = m; for(int i = 1; i <= c; i ++) { x = x / aa[i]; } temp += quick_pow(x, n); return ; } for(int i = b + 1; i <= num; i ++) { aa[cnt + 1] = a[i]; dfs(i, cnt + 1, c); }}int main(){ while(~scanf("%d %d",&n, &m)) { ans = 0; get_prime(m); for(int i = 1; i <= num; i ++) { temp = 0; dfs(0, 0, i); if(i & 1) ans += temp; else ans -= temp; } ans = quick_pow(m, n) - ans; printf("%lld\n",ans); } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>数论</tag>
<tag>容斥原理</tag>
<tag>鸽巢定理</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day25]]></title>
<url>%2F2019%2F08%2F14%2FDay25%2F</url>
<content type="text"><![CDATA[Day25今天讲的是 扩展欧几里得+逆元 ,没咋学会。。。数论是真的难!!!(可能只是对我而言吧)补题逆元解释扩展欧几里得逆元Problem ADescription:度熊手上有一本字典存储了大量的单词,有一次,他把所有单词组成了一个很长很长的字符串。现在麻烦来了,他忘记了原来的字符串都是什么,神奇的是他竟然记得原来那些字符串的哈希值。一个字符串的哈希值,由以下公式计算得到:H(s)=∏{(i≤len(s))i=1}(Si−28) (mod 9973)Si代表 S[i] 字符的 ASCII 码。请帮助度熊计算大字符串中任意一段的哈希值是多少。Input多组测试数据,每组测试数据第一行是一个正整数N,代表询问的次数,第二行一个字符串,代表题目中的大字符串,接下来N行,每行包含两个正整数a和b,代表询问的起始位置以及终止位置。1≤N≤1,0001≤len(string)≤100,0001≤a,b≤len(string)Output对于每一个询问,输出一个整数值,代表大字符串从 a 位到 b 位的子串的哈希值。123456789101112Sample Input2ACMlove20151 118 101testMessage1 1Sample Output6891924088开一个arr数组存入区间1到i的乘积,算[a, b]区间时只需用arr[b]/arr[a-1],然后求出arr[a-1]的逆元即可。code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152#include <bits/stdc++.h>using namespace std;#define ll long long#define INF 0x3f3f3f3fconst int MAXN = 1e5 + 7;ll n, a, b, x, y;ll arr[MAXN];ll exgcd(ll a, ll b, ll &x, ll &y){ if(!b) { x = 1; y = 0; return a; } ll r = exgcd(b, a%b, x, y); ll t = y; y = x - (a/b) * y; x = t; return r;}ll inv(ll a, ll n){ ll gcd = exgcd(a, n, x, y); return (x+n)%n;}int main(){ ios::sync_with_stdio(0); string s; while(cin>>n) { cin>>s; arr[0] = 1; for(int i = 1; i <= s.size(); i++) { arr[i] = arr[i-1]*(s[i-1] - 28)%9973; } while(n--) { cin>>a>>b; cout<<arr[b]*inv(arr[a-1], 9973)%9973<<endl; } } return 0;}A/BDescription:要求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1)。Input数据的第一行是一个T,表示有T组数据。每组数据有两个数n(0 <= n < 9973)和B(1 <= B <= 10^9)。Output对应每组数据输出(A/B)%9973。1234567Sample Input21000 5387 123456789Sample Output79226060code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758//扩展欧几里得算法#include<bits/stdc++.h>using namespace std;int exgcd(int a, int b, int &x, int &y){ if(!b) { x = 1; y = 0; return a; } int r = exgcd(b, a % b, x, y); int t = y; y = x - (a / b) * y; x = t; return r;}int main(){ int t, a, b, mod = 9973; int x, y; cin >> t; while(t --) { cin >> a >> b; exgcd(b, mod, x, y); x = (x + mod) % mod; printf("%d\n", x * a % mod); } return 0;}//试探法#include<bits/stdc++.h>using namespace std;int main(){ int t, a, b; cin >> t; while(t --) { cin >> a >> b; for(int i = 1; i <= 9973; i ++) { if(((i * (b % 9973) % 9973) - a) % 9973 == 0) { printf("%d\n",i); break; } } } return 0;}FansblogDescription:Farmer John keeps a website called ‘FansBlog’ .Everyday , there are many people visited this blog.One day, he find the visits has reached P , which is a prime number.He thinks it is a interesting fact.And he remembers that the visits had reached another prime number.He try to find out the largest prime number Q ( Q < P ) ,and get the answer of Q! Module P.But he is too busy to find out the answer. So he ask you for help. ( Q! is the product of all positive integers less than or equal to n: n! = n (n-1) (n-2) (n-3) … 3 2 1 . For example, 4! = 4 3 2 1 = 24 )InputFirst line contains an number T(1<=T<=10) indicating the number of testcases.Then T line follows, each contains a positive prime number P (1e9≤p≤1e14)OutputFor each testcase, output an integer representing the factorial of Q modulo P.12345Sample Input11000000007Sample Output328400734题意就是问一个质数p,求刚好不大于p的质数q的阶乘对p取模的值首先我们要知道威尔逊定理:对于一个质数p,(p - 1) ! % p = p - 1于是,我们可以得出q ! (q+1) (q + 2) … (p - 2) (p - 1) % p = p-1现在答案就很明显了,ans = (p - 1) inv(p - 1) inv(p - 2) … inv(q + 2) inv(q + 1)q的话就直接暴力求就好了,然后还要注意一下code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354#include<bits/stdc++.h>using namespace std;#define ll long longint check(ll x){ if (x == 1 || !x) return 0; if (x == 2) return 1; ll r = sqrt(x); for (ll i = 3;i <= r;i ++) if (x % i == 0) return 0; return 1;}ll ksc(ll a,ll b,ll p){ return (a*b-(ll)((long double)a/p*b)*p+p)%p;}ll qpow(ll a,ll b,ll p){ ll ans = 1; while (b) { if (b & 1) ans = ksc(ans,a,p); b >>= 1; a = ksc(a,a,p); } return ans;}ll inv(ll x,ll p){ return qpow(x,p-2,p);}int main(){ ios::sync_with_stdio(false); int t; cin>>t; while (t --) { ll p; cin>>p; ll ans = p-1; for (ll x = p - 2;;x -= 2) { if (check(x)) { for (ll i = x + 1;i < p;i ++) ans = ksc(ans,inv(i,p),p); cout<<ans<<'\n'; break; } } } return 0;}RomanticDescription:Girls are clever and bright. In HDU every girl like math. Every girl like to solve math problem!Now tell you two nonnegative integer a and b. Find the nonnegative integer X and integer Y to satisfy Xa + Yb = 1. If no such answer print “sorry” instead.InputThe input contains multiple test cases.Each case two nonnegative integer a,b (0<a, b<=2^31)Outputoutput nonnegative integer X and integer Y, if there are more answers than the X smaller one will be choosed. If no answer put “sorry” instead.12345678Sample Input77 5110 4434 79Sample Output2 -3sorry7 -3很明显的exgcd,如果gcd != 1时就sorry,因为要求的x为非负数,所以写一个while每次加b即可。code:12345678910111213141516171819202122232425262728293031323334353637#include<bits/stdc++.h>using namespace std;int exgcd(int a, int b, int &x, int &y){ if(!b) { x = 1; y = 0; return a; } int r = exgcd(b, a % b, x, y); int t = x; x = y; y = t - (a / b) * y; return r;}int main(){ int a, b, x, y; while(~scanf("%d %d",&a, &b)) { int ans = exgcd(a, b, x, y); if(ans != 1) puts("sorry"); else { while(x < 0) { x += b; y -= a; } printf("%d %d\n", x, y); } } return 0;}Integer DivisibilityDescription:If an integer is not divisible by 2 or 5, some multiple of that number in decimal notation is a sequence of only a digit. Now you are given the number and the only allowable digit, you should report the number of digits of such multiple.For example you have to find a multiple of 3 which contains only 1’s. Then the result is 3 because is 111 (3-digit) divisible by 3. Similarly if you are finding some multiple of 7 which contains only 3’s then, the result is 6, because 333333 is divisible by 7.InputInput starts with an integer T (≤ 300), denoting the number of test cases.Each case will contain two integers n (0 < n ≤ 106 and n will not be divisible by 2 or 5) and the allowable digit (1 ≤ digit ≤ 9).OutputFor each case, print the case number and the number of digits of such multiple. If several solutions are there; report the minimum one.123456789Sample Input33 17 39901 1Sample OutputCase 1: 3Case 2: 6Case 3: 12同余定理的运用,每次在原基础上乘10并加上d就可以了。code:12345678910111213141516171819202122232425#include<bits/stdc++.h>using namespace std;typedef long long ll;const int mod = 1e9;int main(){ int t; ll a, b; cin >> t; int k = 1; while(t --) { cin >> a >> b; int cnt = 1; ll m = b % a; while(m) { m = (m * 10 + b) % a; cnt ++; } printf("Case %d: %d\n", k ++, cnt); } return 0;}Large DivisionDescription:Given two integers, a and b, you should check whether a is divisible by b or not. We know that an integer a is divisible by an integer b if and only if there exists an integer c such that a = b * c.InputInput starts with an integer T (≤ 525), denoting the number of test cases.Each case starts with a line containing two integers a (-10200 ≤ a ≤ 10200) and b (|b| > 0, b fits into a 32 bit signed integer). Numbers will not contain leading zeroes.OutputFor each case, print the case number first. Then print ‘divisible’ if a is divisible by b. Otherwise print ‘not divisible’.123456789101112131415Sample Input6101 1010 67-101 1017678123668327637674887634 10111010000000000000000 256-202202202202000202202202 -101Sample OutputCase 1: divisibleCase 2: divisibleCase 3: divisibleCase 4: not divisibleCase 5: divisibleCase 6: divisible大数取模,和上一题差不多,需要注意的是保存a的值用long long类型,因为在乘的过程中可能会爆int。code:12345678910111213141516171819202122232425262728293031#include<bits/stdc++.h>using namespace std;typedef long long ll;int main(){ int t; string str; ll mod; cin >> t; int k = 1; while(t --) { cin >> str; cin >> mod; int len = str.size(); ll ans = 0; for(int i = 0; i < len; i ++) { if(str[i] == '-') continue; ans = ans * 10 + (str[i] - '0'); ans %= mod; } if(ans % mod) printf("Case %d: not divisible\n", k ++); else printf("Case %d: divisible\n", k ++); } return 0;}青蛙的约会Description:两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面。我们把这两只青蛙分别叫做青蛙A和青蛙B,并且规定纬度线上东经0度处为原点,由东往西为正方向,单位长度1米,这样我们就得到了一条首尾相接的数轴。设青蛙A的出发点坐标是x,青蛙B的出发点坐标是y。青蛙A一次能跳m米,青蛙B一次能跳n米,两只青蛙跳一次所花费的时间相同。纬度线总长L米。现在要你求出它们跳了几次以后才会碰面。Input输入只包括一行5个整数x,y,m,n,L,其中x≠y < 2000000000,0 < m、n < 2000000000,0 < L < 2100000000。Output输出碰面所需要的跳跃次数,如果永远不可能碰面则输出一行”Impossible”1234Sample Input1 2 3 4 5Sample Output4详细题解code:12345678910111213141516171819202122232425262728293031323334353637383940414243#include <bits/stdc++.h>using namespace std;#define ll long long#define INF 0x3f3f3f3fconst int MAXN = (int)1e5 +10;ll exgcd(ll a, ll b, ll &x, ll &y){ if(b == 0) { x = 1, y = 0; return a; } ll r = exgcd(b, a%b, y, x); y -= a/b*x; return r;}int main(){ ll x, y, m, n, l; cin>>x>>y>>m>>n>>l; ll a, b, c, gcd; a = m-n; b = l; c = y-x; if(a<0)//使计算gcd值为正 { a = -a; c = -c; } gcd = exgcd(a, b, x, y); if(c%gcd != 0)//这样得不到整数解 puts("Impossible"); else { x = x*c/gcd; ll t = b/gcd; cout<<(x%t+t)%t<<endl;//x可能为负,这样写保证了值为正 } return 0;}Candy DistributionDescription:Kids like candies, so much that they start beating each other if the candies are not fairly distributed. So on your next party, you better start thinking before you buy the candies.If there are K kids, we of course need K⋅X candies for a fair distribution, where X is a positive natural number. But we learned that always at least one kid looses one candy, so better be prepared with exactly one spare candy, resulting in (K⋅X)+1 candies.Usually, the candies are packed into bags with a fixed number of candies C. We will buy some of these bags so that the above constraints are fulfilled.InputThe first line gives the number of test cases t (0<t<100). Each test case is specified by two integers K and C on a single line, where K is the number of kids and C the number of candies in one bag (1≤K,C≤109). As you money is limited, you will never buy more than 109 candy bags.OutputFor each test case, print one line. If there is no such number of candy bugs to fulfill the above constraints, print “IMPOSSIBLE” instead. Otherwise print the number of candy bags, you want to buy. If there is more than one solution, any will do.12345678910111213Sample Input 1510 510 71337 23123454321 42999999937 142857133Sample Output 1IMPOSSIBLE387214696943166666655题解根据题意,我们可以推出来 Cans + 1 = Kx易知 Kx - Cans = 1,即ax + by = gcd(a,b)所以对于gcd(K , C) == 1,我们用扩展欧几里得求出一个ans,否则输出impossible但是要注意求出的ans是负数的话要通过加K变为正的,然后对于C = 1 的情况要输出K+1code:12345678910111213141516171819202122232425262728293031323334353637383940#include<bits/stdc++.h>using namespace std;#define ll long longll exgcd(ll a,ll b,ll &x,ll &y){ if (!b) { x = 1,y = 0; return a; } int r = exgcd(b,a%b,x,y); int tmp = y; y = x - (a / b) * y; x = tmp; return r;}int main(){ ios::sync_with_stdio(false); int t; cin>>t; while (t --) { ll a,b,x,y; cin>>a>>b; ll _ = exgcd(a,b,x,y); if (_ != 1) cout<<"IMPOSSIBLE"<<'\n'; else { if (b == 1) { cout<<a+1<<'\n'; continue; } while (y <= 0) y += a; cout<<y<<'\n'; } } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>同余定理</tag>
<tag>数论</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day24]]></title>
<url>%2F2019%2F08%2F13%2FDay24%2F</url>
<content type="text"><![CDATA[Day23今天和学长们一起打了学长们的积分赛。。。战况还行补题OJ链接小L的项链切割题目描述小T送给了小L了一串项链。为了方便,我们把项链上形态不同钻石用不同的字母表示。这样小L的项链就变成了一个字符串。小L忽然想把这串项链优美地切割一下,她想把它切割成尽量少的回文项链,啊也就是回文串。求最少的切割次数。输入第一行一个整数T 表示数据组数下面T组数据,每一组数据:只有一行,一个只有小写英文字母的字符串,字符串长度 <= 1000。输出对于每一组数据,输出将这个字符串能切割成最少的回文串所需切割的次数。1234567样例输入2abaaccaabcd样例输出13解法令dp[i]表示从字符串从位置1到位置 i ,最少要切割多少次code:1234567891011121314151617181920212223242526272829303132333435363738394041#include<cstdio>#include<algorithm>#include<cstring>#include<string>using namespace std;const int MAXN = 1e3+7;int dp[MAXN];char s[MAXN];bool check(char *s,int l,int r) { while(l<=r) { if(s[l]!=s[r]) return false; l++; r--; } return true;}int main() { int t; scanf("%d",&t); while(t--) { scanf("%s",s+1); int len = strlen(s+1); memset(dp,0,sizeof(dp)); for(int i=1;i<=len;++i) { dp[i] = MAXN; for(int j=1;j<=i;++j) { if(check(s,j,i)) { if(j==1) dp[i] = 1; else dp[i] = min(dp[i],dp[j-1]+1); } } } printf("%d\n",dp[len]-1); } return 0;}小L的试卷Description:题目描述小L期末考试结束,高高兴兴放假回家了,可是那么多试卷,老师还要加班批改,有n份试卷由k个老师批改,n份试卷进行了密封编号,由于试卷上的做题情况和书写的规范程序不一样,批改不同的试卷用时也可能不一样,每个老师批改试卷的编号顺序是连续的,每位老师批改完分配给自己的试卷就可以离开,问最后离开的老师,最短可能的用时是多少,假定一份试卷让任何一位老师批改用时都是一样的。现在请你设计一种分配方案,使得最后离开的老师用时最短。输入第一行两个整数n,k;(0<k≤n≤1000)第二行n个整数,第i个整数表示批改第i份试卷的用时。输出输出一个整数,表示最后离开的老师所用的最短时间12345样例输入9 3 1 2 3 4 5 6 7 8 9样例输出17二分求解code:12345678910111213141516171819202122232425262728293031323334353637383940414243#include <bits/stdc++.h>using namespace std;typedef long long ll;const ll inf = 0x3f3f3f3f;const int maxn = 1e5 + 10;int n , k;ll a[maxn];bool isok(int x){ bool flag = false; int num = 0; ll temp = 0; for (int i=1; i<=n; i++) { if (a[i] > x) return false; temp += a[i]; if (temp > x) { num ++; temp = a[i]; } } if (temp > 0) num ++; if (num <= k) return true; else return false;}int main(){ scanf("%d%d", &n, &k); for (int i=1; i<=n; i++) scanf("%lld", &a[i]); ll l = 0 , r = inf; while (l <= r) { int mid = (l + r) / 2; if (isok(mid)) r = mid-1; else l = mid + 1; } cout << l << endl; return 0;}小L记单词Description:题目描述小L最近在努力学习英语,但是对一些词组总是记不住,小L小把这些词组中每一个单词的首字母都记一下,这样形成词组的缩写,通过这种方式小L的学习效率明显提高。输入输入有多行,每组测试数据占一行,每行有一个词组,每个词组由一个或多个单词组成;每组的单词个数不超过10个,每个单词由大、小写字母组成;单词长度不超过10,由一个空格分隔这些单词。输出对应每一个词组,输出词组的缩写,缩写都用大写字母,每组输出占一行。1234样例输入end of file样例输出EOFcode:123456789101112131415161718192021222324252627282930313233#include<bits/stdc++.h>using namespace std;typedef long long ll;const int mod = 1e9 + 7;const int maxx = 110;int main(){ string str; char a[maxx]; while(getline(cin,str)) { memset(a, 0, sizeof a); a[0] = str[0]; int len = 1; for(int i = 1; i < str.size(); i ++) { if(str[i - 1] == ' ') a[len ++] = str[i]; else continue; } for(int i = 0; i < len; i ++) { if(a[i] >= 'a' && a[i] <= 'z') a[i] -= 32; else if(a[i] >= 'A' && a[i] <= 'Z') continue; } for(int i = 0; i < len; i ++) cout << a[i]; puts(""); } return 0;}小L的取膜算式Description:题目描述小L想请你帮忙计算一下这个式子的结果(a+b)p MOD p,其中p是质数。输入多组数据第一行一个T表示数据组数接下来T行,每行3个正整数a, b, p且保证p是质数 ,输入数据都是long long范围内的正整数。特别的: p <= 2^62输出对于每一组输入数据,输出正确结果12345样例输入11 2 3样例输出0code:1234567891011121314151617#include<bits/stdc++.h>using namespace std;typedef long long ll;int main(){ ll T, a, b, p; scanf("%lld",&T); while(T --) { scanf("%lld %lld %lld",&a, &b, &p); a %= p; b %= p; ll ans = (a + b) % p; printf("%lld\n",ans); } return 0;}小L玩滚球游戏Description:题目描述小L正在玩滚球游戏,有n个水晶球在轨道上以不同开始位置和速度从近往远的方向滚动,如果两个水晶球在滚动过程中相遇,它们就会融合成一个水晶球,然后以速度较慢的水晶球的速度继续向前滚动, 问经过时间t后,轨道上还有多少水晶球。输入第一行输入两个整数n、t,n代表水晶球的数量(1 <= n <= 105, 0<t<231),t代表时间。接下来n行,每行两个整数,按位置从近到远的顺序给出水晶球的初始位置和速度。输出输出一个整数表示经过时间t后水晶球的数量。123456789样例输入5 30 11 22 33 26 1样例输出3题解:根据题意,移动速度快的球可能会追上在他前面移动速度慢的球,并且追上后合并在一起会变成前面速度慢的球。可以将题意理解为,后面移动速度快的球碰到前面移动速度慢的球则会消失。而且t是固定的值,直接计算每个位置在t秒后移动到的位置,逆向维护一个最靠后的值,检测当前球是否超过这个值。如果超过则说明追上了后面的球当前球会消失。code:123456789101112131415161718192021222324252627282930313233#include <stdio.h>#include <bits/stdc++.h>#define fst first#define sed secondusing namespace std;typedef long long ll;const int INF = 0x3f3f3f3f;const ll LINF = 0x3f3f3f3f3f3f3f3f;const int N = 1e5 + 10;int a[N], v[N];ll b[N]; //经过t秒所处位置int main(){#ifdef LOCAL //freopen("C:/input.txt", "r", stdin);#endif int n, t, m = 0; cin >> n >> t; for (int i = 1; i <= n; ++i) scanf("%d%d", &a[i], &v[i]), b[i] = a[i] + 1LL * v[i] * t; ll p = LINF; for (int i = n; i >= 1; --i) { if (b[i] >= p) m++; p = min(p, b[i]); } cout << n - m << endl; return 0;}小L的区间求和Description:题目描述在给定的一个整数序列中,小L希望找到一个连续的区间,这个区间的和能够被k整除,请你帮小L算一下满足条件的最长的区间长度是多少。输入第一行输入两个整数n、k。(1 <= n <= 105,1<=k<100)接下来一行输入n个整数,表示序列中的数。输出输出一个整数,满足条件区间的最长长度,如果不存在,输出012345样例输入5 71 2 4 1 1样例输出3题解:题解:开一个数组要来记录前n项对K取余的余数,,再开一个数组,用来记录余数第一次出现的位置要点1 当一个 余数数组 的的前几项和为0的时候,从开头到此处的和是K的倍数要点2 当一个余数重复出现的时候,说明从该余数第一次出现的位置(不包括第一次)到该次出现的位置的和味K的倍数(仔细想想还是很有道理的)例如 2%10=2 (2+10)%10 =2 所以当两个余数相同时,期间一定加上了k的倍数。关键就是前面的前n项和的余数数组有点难理解。}code:12345678910111213141516171819202122232425262728#include<bits/stdc++.h>using namespace std;const int maxx = 1e5;int a[maxx], sum[maxx];int main(){ int n, k; scanf("%d %d",&n, &k); map<int, int> mp; for(int i = 1; i <= n; i ++) { scanf("%d",&a[i]); sum[i] = (sum[i - 1] + a[i]) % k; mp[sum[i]] = -1; } int ans = 0; mp[sum[0]] = 0; for(int i = 1; i <= n; i ++) { if(mp[sum[i]] == -1) mp[sum[i]] = i; else ans = max(ans, i - mp[sum[i]]); } printf("%d\n",ans); return 0;}小L的随机数Description:题目描述随机数是生成随机算法的基础,小L准备使用线性同余法(Linear Congruential Method)来生成一个随机数列,这种方法需要设置四个非负整数参数m, a, c, x0按照下面的公式生成出一系列随机数 : Xn+1 = (a * Xn + c) mod m ,小L现在想知道这个数列第n个数是多少,由于他只需要生成小于g的随机数,所以你只需要告诉他Xn mod g的结果即可。输入输入一行6个整数,分别表示m, a, c, X0, n, g 。(n ≤ 106,1 ≤ m, a, c, X0 , g ≤231 − 1)输出一行一个整数表示Xn1234样例输入233 3 3 3 3 333样例输出120code:123456789101112131415161718#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxx = 1e7 + 50;int main(){ ll m, a, c, x, n, g; cin >> m >> a >> c >> x >> n >> g; for(int i = 1; i <= n; i ++) { x = (x * a + c) % m; } printf("%lld\n",x % g); return 0; }小L的直线Description:题目描述小学时期的小L发现自己很有艺术细胞,于是买了一块画板,但是他的绘画水平使得他只能连接两点画出一条线段。有一天他决定在一张有n个点的图上作画,即他可以把这n个点任意连接。大家认为平行线是非常不美观的,于是他想知道自己最多能画多少条直线使整张画不出现平行线。输入第一行输入一个整数n (1 <= n <= 200)接下来n行每行两个整数代表每个点的坐标x, y (-1000 <= x, y <= 1000)输出一行一个整数为能画出最多的两两不平行的直线条数12345678样例输入4-1 1-2 00 01 1样例输出4code:12345678910111213141516171819202122232425262728293031323334353637#include<bits/stdc++.h>using namespace std;const int maxx = 1e3;struct node{ int x, y;}e[maxx];int main(){ int n; set<double> se; scanf("%d",&n); for(int i = 0; i < n; i ++) cin >> e[i].x >> e[i].y; double ans; int cnt = 0; for(int i = 0; i < n; i ++) { for(int j = 0; j < n; j ++) { if(i == j) continue; else { if((e[j].x - e[i].x) == 0) cnt = 1; else { ans = 1.0 * (e[j].y - e[i].y) / (e[j].x - e[i].x); se.insert(ans); } } } }// for(set<double> :: iterator it = se.begin(); it != se.end(); it ++)// cout << *it << " "; cout << se.size() + cnt << endl; return 0;}小L的长方形Description:题目描述在数学课上,老师发给小L一根铁丝,让小L将这根铁丝围成一个长方形。要求这个长方形的长是宽的3倍,并且计算它的面积。输入仅一个整数a,表示铁丝的长度(a≤10000)。输出输出三个数,分别表示长方形的长、宽、面积。如果计算结果是整数,则输出整数结果(没有小数部分);如果不是,则保留三位小数。每个数之间用一个空格隔开。1234样例输入36样例输出13.500 4.500 60.750code:123456789101112131415161718#include<bits/stdc++.h>using namespace std;int main(){ double x; double l; cin >> l; x = l / 8; double ans = 3 * x * x; if(x == (int)x) printf("%.0lf %.0lf %.0lf\n",3 * x, x, ans); else printf("%.3lf %.3lf %.3lf\n",3 * x, x, ans); return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day23]]></title>
<url>%2F2019%2F08%2F12%2FDay23%2F</url>
<content type="text"><![CDATA[Day23今天讲的是 算术基本原理 ,没咋学会。。。有是自闭的一天补题数论解释真的有必要好好看一下数论算术基本原理解释简介算术基本定理,又称为正整数的唯一分解定理,即:每个大于1的自然数,要么本身就是质数,要么可以写为2个或以上的质数的积,而且这些质因子按大小排列之后,写法仅有一种方式。例如: 6936 = 2^3 3 17^2, 1200 = 2^4 3 5^2算术基本定理的内容由两部分构成:分解的存在性:分解的唯一性,即若不考虑排列的顺序,正整数分解为素数乘积的方式是唯一的。算术基本定理是初等数论中一个基本的定理,也是许多其他定理的逻辑支撑点和出发点。详情链接假代码模板12345678910111213141516171819202122232425262728#include<stdio.h>#include<algorithm>#include<map>using namespace std;int a[1000];map<int,int>ma;int main(){ int n; int num=0; scanf("%d",&n); int m=n; for(int i=2;i*i<=n;i++) { if(n%i==0) a[num++]=i; while(n%i==0) { ma[i]++; n=n/i; } } if(n>1) a[num++]=n,ma[n]++; for(int i=0;i<num;i++) { printf("%d %d\n",a[i],ma[a[i]]); } return 0;}Smith NumbersDescription:While skimming his phone directory in 1982, Albert Wilansky, a mathematician of Lehigh University,noticed that the telephone number of his brother-in-law H. Smith had the following peculiar property: The sum of the digits of that number was equal to the sum of the digits of the prime factors of that number. Got it? Smith’s telephone number was 493-7775. This number can be written as the product of its prime factors in the following way:4937775= 355*65837The sum of all digits of the telephone number is 4+9+3+7+7+7+5= 42,and the sum of the digits of its prime factors is equally 3+5+5+6+5+8+3+7=42. Wilansky was so amazed by his discovery that he named this kind of numbers after his brother-in-law: Smith numbers.As this observation is also true for every prime number, Wilansky decided later that a (simple and unsophisticated) prime number is not worth being a Smith number, so he excluded them from the definition.Wilansky published an article about Smith numbers in the Two Year College Mathematics Journal and was able to present a whole collection of different Smith numbers: For example, 9985 is a Smith number and so is 6036. However,Wilansky was not able to find a Smith number that was larger than the telephone number of his brother-in-law. It is your task to find Smith numbers that are larger than 4937775!InputThe input file consists of a sequence of positive integers, one integer per line. Each integer will have at most 8 digits. The input is terminated by a line containing the number 0.OutputFor every number n > 0 in the input, you are to compute the smallest Smith number which is larger than n,and print it on a line by itself. You can assume that such a number exists.12345Sample Input49377740Sample Output4937775code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859#include<stdio.h>#include<algorithm>#include<map>#include<cmath>#include<cstring>#include<iostream>using namespace std;const int maxx = 1e5;int a[1000];int num;map<int,int>ma;bool isprime(int n){ for(int i = 2; i * i <= n; i ++) { if(n % i == 0) return false; } return true;}int sum(int n){ int i, sum = 0; while(n) { i = n % 10; sum += i; n /= 10; } return sum;}int cut(int n){ //分治的思想,如果是素数,就返回sum,否则,将该数分成两部分,再求各部分的质因子的sum if(isprime(n)) return sum(n); for(int i = (int)sqrt(n + 0.5); i > 1; i --) { if(n % i == 0) return cut(i) + cut(n / i); }}int main(){ int n; while(~scanf("%d",&n)) { if(n == 0) break; while(n ++) { if(!isprime(n) && sum(n) == cut(n)) break; } printf("%d\n",n); } return 0;}Pairs Forming LCMDescription:Find the result of the following code:1234567long long pairsFormLCM( int n ) { long long res = 0; for( int i = 1; i <= n; i++ ) for( int j = i; j <= n; j++ ) if( lcm(i, j) == n ) res++; // lcm means least common multiple return res;}A straight forward implementation of the code may time out. If you analyze the code, you will find that the code actually counts the number of pairs (i, j) for which lcm(i, j) = n and (i ≤ j).InputInput starts with an integer T (≤ 200), denoting the number of test cases.Each case starts with a line containing an integer n (1 ≤ n ≤ 1014).OutputFor each case, print the case number and the value returned by the function ‘pairsFormLCM(n)’.123456789101112131415161718192021222324252627282930313233Sample Input152346810121518202124252729Sample OutputCase 1: 2Case 2: 2Case 3: 3Case 4: 5Case 5: 4Case 6: 5Case 7: 8Case 8: 5Case 9: 8Case 10: 8Case 11: 5Case 12: 11Case 13: 3Case 14: 4Case 15: 2code:1234567891011121314151617181920212223242526272829303132333435363738394041424344#include<bits/stdc++.h>using namespace std;const int maxn = 1e7;typedef long long ll;int p[maxn/10],m;//素数的数组开始1e7会REbool vis[maxn];void init(){ m=0; for(int i=2;i<maxn;i++) { if(!vis[i]) p[m++]=i; for(int j=0;j<m&&p[j]*i<maxn;j++) { vis[p[j]*i]=1; if(i%p[j]==0) break; } }}int main(){ init(); ll n,ans,c; int t,f=0; cin>>t; while(t--) { cin>>n; ans=1; for(int i=0;i<m;i++) { if(p[i]*p[i]>n) break; c=0; while(n%p[i]==0) { n/=p[i]; ++c; } if(c) ans*=c*2+1; } if(n>1) ans*=1*2+1; printf("Case %d: %lld\n",++f,ans/2+1); }}Ekka DokkaDescription:Ekka and his friend Dokka decided to buy a cake. They both love cakes and that’s why they want to share the cake after buying it. As the name suggested that Ekka is very fond of odd numbers and Dokka is very fond of even numbers, they want to divide the cake such that Ekka gets a share of N square centimeters and Dokka gets a share of M square centimeters where N is odd and M is even. Both N and M are positive integers.They want to divide the cake such that N * M = W, where W is the dashing factor set by them. Now you know their dashing factor, you have to find whether they can buy the desired cake or not.InputInput starts with an integer T (≤ 10000), denoting the number of test cases.Each case contains an integer W (2 ≤ W < 263). And W will not be a power of 2.OutputFor each case, print the case number first. After that print “Impossible” if they can’t buy their desired cake. If they can buy such a cake, you have to print N and M. If there are multiple solutions, then print the result where M is as small as possible.123456789Sample Input310512Sample OutputCase 1: 5 2Case 2: ImpossibleCase 3: 3 4code:12345678910111213141516171819202122232425262728293031#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxx = 1e5;int main(){ int T; ll w; scanf("%d",&T); int k = 0; while(T --) { scanf("%lld",&w); ll n = 1, m = 1; if(w % 2 == 0) { while(w % 2 == 0) { n = n * 2; w = w / 2; } printf("Case %d: %lld %lld\n", ++ k, w, n); } else printf("Case %d: Impossible\n",++ k); } return 0; }Sum of Consecutive IntegersDescription:Given an integer N, you have to find the number of ways you can express N as sum of consecutive integers. You have to use at least two integers.For example, N = 15 has three solutions, (1+2+3+4+5), (4+5+6), (7+8).InputInput starts with an integer T (≤ 200), denoting the number of test cases.Each case starts with a line containing an integer N (1 ≤ N ≤ 1014).OutputFor each case, print the case number and the number of ways to express N as sum of consecutive integers.12345678910111213Sample Input510151236828495Sample OutputCase 1: 1Case 2: 3Case 3: 1Case 4: 2Case 5: 47code:12345678910111213141516171819202122232425262728293031323334353637#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxn = 1e7+10;ll n,p[maxn/10];bool is[maxn];int t,ca,pos;void init(){ for(int i=2;i<maxn;i++) { if(!is[i]) p[pos++]=i; for(int j=0;j<pos&&i*p[j]<maxn;j++) { is[i*p[j]]=1; if(i%p[j]==0) break; } }}int main(){ cin>>t; init(); while(t--) { ll ans=1; cin>>n; for(int i=0;i<pos&&p[i]*p[i]<=n;i++) { ll cnt=0;a while(n%p[i]==0) cnt++,n/=p[i]; if(i) ans*=cnt+1; } if(n>2) ans*=2; printf("Case %d: %lld\n",++ca,ans-1); }}Aladdin and the Flying CarpetDescription:It’s said that Aladdin had to solve seven mysteries before getting the Magical Lamp which summons a powerful Genie. Here we are concerned about the first mystery.Aladdin was about to enter to a magical cave, led by the evil sorcerer who disguised himself as Aladdin’s uncle, found a strange magical flying carpet at the entrance. There were some strange creatures guarding the entrance of the cave. Aladdin could run, but he knew that there was a high chance of getting caught. So, he decided to use the magical flying carpet. The carpet was rectangular shaped, but not square shaped. Aladdin took the carpet and with the help of it he passed the entrance.Now you are given the area of the carpet and the length of the minimum possible side of the carpet, your task is to find how many types of carpets are possible. For example, the area of the carpet 12, and the minimum possible side of the carpet is 2, then there can be two types of carpets and their sides are: {2, 6} and {3, 4}.InputInput starts with an integer T (≤ 4000), denoting the number of test cases.Each case starts with a line containing two integers: a b (1 ≤ b ≤ a ≤ 1012) where a denotes the area of the carpet and b denotes the minimum possible side of the carpet.OutputFor each case, print the case number and the number of possible carpets.1234567Sample Input210 212 2Sample OutputCase 1: 1Case 2: 2code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253#include<bits/stdc++.h>using namespace std;const int maxn = 1e6;typedef long long ll;ll p[maxn],pos,vis[maxn];void init(){ pos=0; for(int i=2;i<maxn;i++) { if(!vis[i]) p[pos++]=i; for(int j=0;j<pos&&p[j]*i<maxn;j++) { vis[p[j]*i]=1; if(i%p[j]==0) break; } }}int main(){ ll t,a,b,l=0; scanf("%lld",&t); init(); while(t--) { ll now=0,ans=1,aa,net=0; scanf("%lld %lld",&a,&b); if(b*b>=a) { printf("Case %d: 0\n",++l); continue; } aa=a; for(int i=0;i<pos&&p[i]<=a;i++) { int c=0; while(a%p[i]==0) { a/=p[i]; c++; } ans*=(c+1); } if(a>1) ans*=2; ans/=2; for(ll i=1;i<b;i++) { if(aa%i==0) ans--; } printf("Case %lld: %lld\n",++l,ans); }}Minimum Sum LCMDescription:LCM (Least Common Multiple) of a set of integers is defined as the minimum number, which is amultiple of all integers of that set. It is interesting to note that any positive integer can be expressedas the LCM of a set of positive integers. For example 12 can be expressed as the LCM of 1, 12 or 12, 12 or 3, 4 or 4, 6 or 1, 2, 3, 4 etc.In this problem, you will be given a positive integer N. You have to find out a set of at least two positive integers whose LCM is N. As infinite such sequences are possible, you have to pick the sequence whose summation of elements is minimum. We will be quite happyif you just print the summation of the elements of this set. So, for N = 12, you should print 4+3 = 7 as LCM of 4 and 3 is 12 and 7 is the minimum possible summation.InputThe input file contains at most 100 test cases. Each test case consists of a positive integer N (1 ≤ N ≤ 2^31 − 1).Input is terminated by a case where N = 0. This case should not be processed. There can be at most 100 test cases.OutputOutput of each test case should consist of a line starting with ‘Case #: ’ where # is the test case number. It should be followed by the summation as specified in the problem statement. Look at the output for sample input for details.123456789Sample Input121050Sample OutputCase 1: 7Case 2: 7Case 3: 6code:12345678910111213141516171819202122232425262728#include<bits/stdc++.h>using namespace std;typedef long long ll;int main(){ ll n,cas=1; while(cin>>n&&n) { ll ans=0,cnt=0,x=n; for(ll i=2;i*i<=n;i++) { ll mid=1; if(n%i==0) { cnt++; while(n%i==0) { n/=i; mid*=i; } ans+=mid; } } if(n==x) ans=x+1; else if(n!=1 || cnt == 1) ans+=n; printf("Case %lld: %lld\n",cas++,ans); }}GCD and LCMDescription:Given two positive integers G and L, could you tell me how many solutions of (x, y, z) there are, satisfying that gcd(x, y, z) = G and lcm(x, y, z) = L?Note, gcd(x, y, z) means the greatest common divisor of x, y and z, while lcm(x, y, z) means the least common multiple of x, y and z.Note 2, (1, 2, 3) and (1, 3, 2) are two different solutions.InputFirst line comes an integer T (T <= 12), telling the number of test cases.The next T lines, each contains two positive 32-bit signed integers, G and L.It’s guaranteed that each answer will fit in a 32-bit signed integer.OutputFor each test case, print one line with the number of solutions satisfying the conditions above.1234567Sample Input26 727 33Sample Output720code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081#include<iostream>#include<stdio.h>using namespace std;typedef long long ll;int main(){ int T; scanf("%d",&T); while(T --) { ll L, G; scanf("%lld %lld",&G, &L); ll n = L / G; //L % G != 0 无解 ll ans = L % G ? 0 : 1; for(ll i = 2; i * i <= n; i ++) { //m是n某一个素因子的幂级数 ll m = 0; if(n % i != 0) continue; while(n % i == 0) { m ++; n = n / i; } ans = ans * 6 * m; } //n仍然不等于1说明此时n是一个大素数 if(n != 1) ans *= 6; printf("%lld\n",ans); } return 0;}/*显然若lcm%gcd!=0时无解,令n=lcm/gcd,对n质因数分解后得到n=p1^k1*p2^k2*…*pm^km,那么必然有a/g=p1^a1*p2^a2*…*pm^amb/g=p1^b1*p2^b2*…*pm^bmc/g=p1^c1*p2^c2*…*pm^cm所以对于任意i(1<=i<=m),都有min(ai,bi,ci)=0,max(ai,bi,ci)=ki,当ai,bi,ci三者之中居中者取1~ki-1时,总共有6*(ki-1)种情况,当取0或者ki时,有2*3=6种情况,所以对于每个i,都有6*(ki-1)+6=6*ki种情况,所以枚举n的所有质因子幂级数k每次累乘6*k即可*///另一种代码#include<cstdio>typedef long long ll;int main(){ int t; long long m, n, ans, i, count; scanf("%d", &t); while (t--) { scanf("%lld%lld", &m, &n); if (n % m) puts("0");///注意特判 else { n /= m; ans = 1; for (i = 2; i * i <= n; i += 2)///不用求素数,因为范围很小(注意n在不断减小) { if (n % i == 0) { count = 0; while (n % i == 0) { n /= i; ++count; } ans *= 6 * count; } if (i == 2) --i;///小技巧 } if (n > 1) ans *= 6; printf("%lld\n", ans); } } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>数论</tag>
<tag>算术基本原理</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day22]]></title>
<url>%2F2019%2F08%2F10%2FDay22%2F</url>
<content type="text"><![CDATA[Day22有是一次积分赛有是自闭的一天补题wzy的大冒险——出发前的清理Description:由于上次学弟们没有ak,导致许多蚂蚁被留下了。wzy在出发冒险前请来了一只食蚁兽帮忙清理。现在出现了一只食蚁兽。每个蚂蚁都有wzy给它的一个编号,食蚁兽要吃蚂蚁必须要确认蚂蚁的编号X是否满足要求,如下:X的质因子的种类不超过13种X的食蚁数是个素数(食蚁数的定义见最下方提示)X的食蚁数是个回文数如果都满足则输出 YES ,否则输出 NO输入格式第一行给定一个T,(1≤T≤1e5)接下来T行,每行给出数字X,(1≤X≤1e17)输出格式每行输出 YES 或者 NO1234567891011121314样例input31216661116661312333outputNONOYES提示补充:1. 回文数至少为两位数,如 131 、 222. 如果X的长度为 len1 ,令 len2=⌊len1/2⌋,则 X 的前 len2 位形成的数是它的食蚁数code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219//打表做法//借用别人的代码#include <bits/stdc++.h>#define PI acos(-1)const int NN = 777;typedef long long ll;using namespace std;int prime[NN] = {11,101,131,151,181,191,313,353,373,383,727,757,787,797,919,929,10301,10501,10601,11311,11411,12421,12721,12821,13331,13831,13931,14341,14741,15451,15551,16061,16361,16561,16661,17471,17971,18181,18481,19391,19891,19991,30103,30203,30403,30703,30803,31013,31513,32323,32423,33533,34543,34843,35053,35153,35353,35753,36263,36563,37273,37573,38083,38183,38783,39293,70207,70507,70607,71317,71917,72227,72727,73037,73237,73637,74047,74747,75557,76367,76667,77377,77477,77977,78487,78787,78887,79397,79697,79997,90709,91019,93139,93239,93739,94049,94349,94649,94849,94949,95959,96269,96469,96769,97379,97579,97879,98389,98689,1003001,1008001,1022201,1028201,1035301,1043401,1055501,1062601,1065601,1074701,1082801,1085801,1092901,1093901,1114111,1117111,1120211,1123211,1126211,1129211,1134311,1145411,1150511,1153511,1160611,1163611,1175711,1177711,1178711,1180811,1183811,1186811,1190911,1193911,1196911,1201021,1208021,1212121,1215121,1218121,1221221,1235321,1242421,1243421,1245421,1250521,1253521,1257521,1262621,1268621,1273721,1276721,1278721,1280821,1281821,1286821,1287821,1300031,1303031,1311131,1317131,1327231,1328231,1333331,1335331,1338331,1343431,1360631,1362631,1363631,1371731,1374731,1390931,1407041,1409041,1411141,1412141,1422241,1437341,1444441,1447441,1452541,1456541,1461641,1463641,1464641,1469641,1486841,1489841,1490941,1496941,1508051,1513151,1520251,1532351,1535351,1542451,1548451,1550551,1551551,1556551,1557551,1565651,1572751,1579751,1580851,1583851,1589851,1594951,1597951,1598951,1600061,1609061,1611161,1616161,1628261,1630361,1633361,1640461,1643461,1646461,1654561,1657561,1658561,1660661,1670761,1684861,1685861,1688861,1695961,1703071,1707071,1712171,1714171,1730371,1734371,1737371,1748471,1755571,1761671,1764671,1777771,1793971,1802081,1805081,1820281,1823281,1824281,1826281,1829281,1831381,1832381,1842481,1851581,1853581,1856581,1865681,1876781,1878781,1879781,1880881,1881881,1883881,1884881,1895981,1903091,1908091,1909091,1917191,1924291,1930391,1936391,1941491,1951591,1952591,1957591,1958591,1963691,1968691,1969691,1970791,1976791,1981891,1982891,1984891,1987891,1988891,1993991,1995991,1998991,3001003,3002003,3007003,3016103,3026203,3064603,3065603,3072703,3073703,3075703,3083803,3089803,3091903,3095903,3103013,3106013,3127213,3135313,3140413,3155513,3158513,3160613,3166613,3181813,3187813,3193913,3196913,3198913,3211123,3212123,3218123,3222223,3223223,3228223,3233323,3236323,3241423,3245423,3252523,3256523,3258523,3260623,3267623,3272723,3283823,3285823,3286823,3288823,3291923,3293923,3304033,3305033,3307033,3310133,3315133,3319133,3321233,3329233,3331333,3337333,3343433,3353533,3362633,3364633,3365633,3368633,3380833,3391933,3392933,3400043,3411143,3417143,3424243,3425243,3427243,3439343,3441443,3443443,3444443,3447443,3449443,3452543,3460643,3466643,3470743,3479743,3485843,3487843,3503053,3515153,3517153,3528253,3541453,3553553,3558553,3563653,3569653,3586853,3589853,3590953,3591953,3594953,3601063,3607063,3618163,3621263,3627263,3635363,3643463,3646463,3670763,3673763,3680863,3689863,3698963,3708073,3709073,3716173,3717173,3721273,3722273,3728273,3732373,3743473,3746473,3762673,3763673,3765673,3768673,3769673,3773773,3774773,3781873,3784873,3792973,3793973,3799973,3804083,3806083,3812183,3814183,3826283,3829283,3836383,3842483,3853583,3858583,3863683,3864683,3867683,3869683,3871783,3878783,3893983,3899983,3913193,3916193,3918193,3924293,3927293,3931393,3938393,3942493,3946493,3948493,3964693,3970793,3983893,3991993,3994993,3997993,3998993,7014107,7035307,7036307,7041407,7046407,7057507,7065607,7069607,7073707,7079707,7082807,7084807,7087807,7093907,7096907,7100017,7114117,7115117,7118117,7129217,7134317,7136317,7141417,7145417,7155517,7156517,7158517,7159517,7177717,7190917,7194917,7215127,7226227,7246427,7249427,7250527,7256527,7257527,7261627,7267627,7276727,7278727,7291927,7300037,7302037,7310137,7314137,7324237,7327237,7347437,7352537,7354537,7362637,7365637,7381837,7388837,7392937,7401047,7403047,7409047,7415147,7434347,7436347,7439347,7452547,7461647,7466647,7472747,7475747,7485847,7486847,7489847,7493947,7507057,7508057,7518157,7519157,7521257,7527257,7540457,7562657,7564657,7576757,7586857,7592957,7594957,7600067,7611167,7619167,7622267,7630367,7632367,7644467,7654567,7662667,7665667,7666667,7668667,7669667,7674767,7681867,7690967,7693967,7696967,7715177,7718177,7722277,7729277,7733377,7742477,7747477,7750577,7758577,7764677,7772777,7774777,7778777,7782877,7783877,7791977,7794977,7807087,7819187,7820287,7821287,7831387,7832387,7838387,7843487,7850587,7856587,7865687,7867687,7868687,7873787,7884887,7891987,7897987,7913197,7916197,7930397,7933397,7935397,7938397,7941497,7943497,7949497,7957597,7958597,7960697,7977797,7984897,7985897,7987897,7996997,9002009,9015109,9024209,9037309,9042409,9043409,9045409,9046409,9049409,9067609,9073709,9076709,9078709,9091909,9095909,9103019,9109019,9110119,9127219,9128219,9136319,9149419,9169619,9173719,9174719,9179719,9185819,9196919,9199919,9200029,9209029,9212129,9217129,9222229,9223229,9230329,9231329,9255529,9269629,9271729,9277729,9280829,9286829,9289829,9318139,9320239,9324239,9329239,9332339,9338339,9351539,9357539,9375739,9384839,9397939,9400049,9414149,9419149,9433349,9439349,9440449,9446449,9451549,9470749,9477749,9492949,9493949,9495949,9504059,9514159,9526259,9529259,9547459,9556559,9558559,9561659,9577759,9583859,9585859,9586859,9601069,9602069,9604069,9610169,9620269,9624269,9626269,9632369,9634369,9645469,9650569,9657569,9670769,9686869,9700079,9709079,9711179,9714179,9724279,9727279,9732379,9733379,9743479,9749479,9752579,9754579,9758579,9762679,9770779,9776779,9779779,9781879,9782879,9787879,9788879,9795979,9801089,9807089,9809089,9817189,9818189,9820289,9822289,9836389,9837389,9845489,9852589,9871789,9888889,9889889,9896989,9902099,9907099,9908099,9916199,9918199,9919199,9921299,9923299,9926299,9927299,9931399,9932399,9935399,9938399,9957599,9965699,9978799,9980899,9981899,9989899};bool isprime(ll N){ string str = std::to_string(N); ll n = 0; for(int i = 0;i<str.size()/2;i++){ n = n*10+(str[i]-'0'); } if(n == 1||n ==0) return false; int t = lower_bound(prime,prime+NN,n)-prime; if(t == NN) return false; if(prime[t] == n) return true; return false;}ll ksm(ll a,ll b){ ll res = 1; while(b){ if(b&1) res = res*a; a = a*a; b<<=1; } return res;}bool divide(ll x){ int coun = 0; for(int i = 2;i<=x/i && i<=100;i++){ if(x%i ==0 ){ while(x%i ==0) x/=i; coun++; if(coun>13) return false; } } return true;}int main(){ ll T,N; cin>>T; while(T--){ scanf("%lld",&N); if(!isprime(N)){ cout<<"NO"<<endl; continue; } if(!divide(N)){ cout<<"NO"<<endl; continue; } cout<<"YES"<<endl; } return 0;}//非打表做法//#pragma GCC optimize(3)#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>#include <cmath>#include <map>#include <set>#include <stack>#include <ctime>#include <queue>#define INF 0x3f3f3f3fusing namespace std;typedef long long ll;typedef unsigned long long ull;const int MAXN = 1e7+7;int prime[MAXN];int visit[MAXN];void Prime(){ //网上随便找了个素筛板子,好像visit[i]==0表示素数(为什么两个数组不反过来用 memset(visit,0, sizeof(visit)); memset(prime, 0, sizeof(prime)); for (int i = 2;i <= MAXN; i++) { // cout<<" i = "<<i<<endl; if (!visit[i]) { prime[++prime[0]] = i; //纪录素数, 这个prime[0] 相当于 cnt,用来计数 } for (int j = 1; j <=prime[0] && i*prime[j] <= MAXN; j++) { visit[i*prime[j]] = 1; if (i % prime[j] == 0) { break; } } }}char s[20];char w[20];int main(){ // ll q; // q = 2*3*5*7*11*13; // q = q*17* 19* 23*29*31*37*41; //13:304250263527210 14:13082761331670030 Prime(); int i, k, flag, n; ll a, b; int t; cin>>t; while(t--) { scanf("%lld", &a); if(a<=1000) //食蚁数长度在两位及以上,所以a的长度在四位及以上 { printf("NO\n"); continue; } b = a; k = 0; flag = 1; while(b) //统计a的长度并且转换为字符串 { s[k++] = b%10; b/=10; } n = k; //长度 if(n>=16) //a长度为16、17位,食蚁数长度为8位;或者a==100000000000000000,食蚁数==100000000 { printf("NO\n"); continue; } for(i=0; i<k/2; i++) //取食蚁数字符串 w[i] = s[k-i-1]; k/=2; //k为食蚁数位数 if(!(k%2)) //一个回文数如果位数为偶数位那么它一定不是素数(11除外) { if(a/100==11 || a/1000==11) printf("YES\n"); else printf("NO\n"); continue; } for(i=0; i<k/2; i++) //检查回文串 { if(w[i] != w[k-i-1]) { flag = 0; break; } } n = a/pow(10, n-k); if(flag && !visit[n]) printf("YES\n"); else printf("NO\n"); } return 0;}wzy的大冒险——出发咯QAQDescription:wzy踏上了冒险的旅程。现在他从地精手里买了一份地图,地图上有n个城镇。他从第一个城镇出发,走向(没钱只能走)第n个城镇,现在,请你帮wzy找到一条最短的路径,并倒序(从n到1)输出一条最短路径。举个栗子:如果有两条路径6 4 3 1和6 5 2 1,我们选择6 4 3 1这条。地精小提示:路是单向的QAQ。输入格式第一行两个数n,m ,(1≤n≤10^3,1≤m≤10^3)接下来m行,每行三个数x,y,z,表示点 x 与点 y 之间有一条权值为 z 的有向边 (1≤x,y,z≤10^3).输出格式第一行一个整数表示 1 到 n 的最短距离;第二行倒序输出这条路径。12345678910111213样例input5 71 2 691 3 871 4 792 5 942 3 103 5 794 5 43output1225 4 1code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859#include<bits/stdc++.h>using namespace std;const int maxn=1e3+10;const int INF=0x3f3f3f3f;int a[maxn][maxn],dis[maxn],f[maxn];bool vis[maxn];int n,m,u,v,w;struct node{ int d,id; bool friend operator < (node a,node b) { return a.d > b.d; }};priority_queue<node> q;void solve(){ for(int i=1;i<=n;i++) dis[i]=INF; dis[1]=0; q.push(node{dis[1],1}); while(!q.empty()) { node p=q.top(); q.pop(); int mid=p.id; if(vis[mid]==1) continue; vis[mid]=1; for(int i=1;i<=n;i++) { if(dis[i]>dis[mid]+a[mid][i]) { dis[i]=dis[mid]+a[mid][i]; f[i]=mid;//这就是记录路径所用到的数组 q.push(node{dis[i],i}); } } } cout<<dis[n]<<endl;}int main(){ cin>>n>>m; f[1]=1; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) a[i][j]=INF; for(int i=1;i<=m;i++) { cin>>u>>v>>w; a[u][v]=w; } solve(); cout<<n<<" "; while(f[n]!=n)//输出最短路径所用到的查找 { cout<<f[n]<<" "; n=f[n]; }}wzy的大冒险——数学王国Description:wzy这一次来到了数学王国,加号国王为了考验他,找来了一个数字n,告诉了wzy这个数字的阶乘的末尾零的个数Q,猜错的话就要把wzy赶出去。现在请你帮帮wzy求这个数最小为多少。若不存在输出”impossible”(输出不带引号)。输入格式输入数据包含T组(1≤T≤10000)每一组数据包含一个数字Q (0≤Q≤10^8)输出格式对于每一组数据请输出这个数字n,否则输出”impossible”(输出不带引号)。123456789101112131415样例input3125output510impossibleinput110000000output40000010code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxx = 1e9;int solve(ll x){ ll ans = 0; while(x) { ans = ans + (x / 5); x = x / 5; } return ans;}int er_fen(ll n){ ll l = 0, r = maxx; ll mid; while(l <= r) { mid = l + r; if(solve(mid / 2) >= n) r = mid / 2 - 1; else l = mid / 2 + 1; } return r;}int main(){ int T; cin >> T; while(T --) { ll x, y; cin >> x; y = er_fen(x) + 1; if(solve(y) == x) printf("%lld\n",y); else puts("impossible"); } return 0;}wzy的大冒险——a+b问题Description:每个ACMer都是从a+b问题开始的,今天wzy翻到了他的第一个a+b程序,并想让你来输出它#include<stdio.h>int main(){int a,b;scanf(“%d %d”,&a,&b);int c=a+b;printf(“%d\n”,c);return 0;}输入格式本题无输入输出格式将上面代码输出123456789101112样例inputoutput#include<stdio.h>int main(){int a,b;scanf("%d %d",&a,&b);int c=a+b;printf("%d\n",c);return 0;}code:123456789101112131415161718192021#include<bits/stdc++.h>using namespace std;int main(){ printf("#include<stdio.h>\n"); printf("int main()\n"); printf("{\n"); printf("int a,b;\n"); printf("scanf(\""); cout << "%d " << "%d"; printf("\",&a,&b);\n"); printf("int c=a+b;\n"); printf("printf(\""); cout << "%d\\n"; printf("\",c);\n"); printf("return 0;\n"); printf("}\n"); return 0;}wzy的大冒险——炉石传说Description:wzy来到了炉石传说的世界。他发现他现在有n个攻击力为ai的随从,每个随从只能攻击一次。对面的boss有m个血量为bi的具有嘲讽的随从(嘲讽即为你必须先把这些怪物击败才可攻击boss)。当我方随从攻击力大于等于敌方随从血量时,敌方随从死亡。由于boss的强力技能,对方的随从只能受到一次攻击,受到攻击后无法再一次受到攻击。(你无法使两个随从都攻击对方的同一个的随从)。wzy必须先干掉对方的所有随从才能使用剩下的随从攻击boss本身。对方boss有k的血量,现在请问wzy能否干掉敌方boss回归现实世界?输入格式第一行为三个数n,m,k。n 为wzy拥有的随从数量,m为boss拥有的随从数量,k为boss血量。第二行为n个数,分别是wzy随从的攻击力;第三行为m个数,分别是boss随从的血量。以上数据范围均在[1,100]范围内输出格式如果胜利输出Win,否则输出Lose1234567样例input4 3 22 4 6 83 5 7outputWincode:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxx = 101;int cmp(int a, int b){ return a > b;}int a[maxx], b[maxx];int main(){ int n, m, k; cin >> n >> m >> k; memset(a, 0, sizeof a); for(int i = 1; i <= n; i ++) cin >> a[i]; for(int i = 1; i <= m; i ++) cin >> b[i]; sort(a + 1, a + n + 1); sort(b + 1, b + m + 1); int flag = 0; if(n <= m) puts("Lose"); else { int ans = 0; if(a[n] >= b[m]) { for(int i = 1; i <= m; i ++) { for(int j = 1;j <= n; j ++) { if(a[j] < b[i]) { ans += a[j]; a[j] = 0; } else { a[j] = 0; b[i] = 0; break; } } } for(int i = 1; i <= n; i ++) ans += a[i]; for(int i = 1; i <= m; i ++) if(b[i] != 0) flag = 1; if(ans >= k && flag == 0) puts("Win"); else puts("Lose"); } else puts("Lose"); } return 0;}wzy的大冒险——接龙红包Description:最近QQ更新了一个新的功能–“接龙红包”,会长作为算协的土豪,便开始在群里发红包,wzy总是抢的又快又准,现在他开始研究成语接龙的奥秘。现在QQ的词库里面有n种成语,每种成语由一个只由小写字母组成的字符串表示,现在wzy发现了一个问题,如果有个同学说了一个成语,但是在词库里找不到可以接在它后面的成语(即找不到一个成语的首字母和该成语的尾字母相同),这样的成语被称为死局成语,现在zy想知道在词库里面有多少这样的死局成语。输入格式第一行输入n,接下来n行每行输入一个字符串代表一个成语s。(1≤n≤100,1≤|s|≤20)输出格式第一行输出死局成语的个数m。接下来m行每行输出一个死局成语,输出顺序应和输入顺序保持一致。12345678910111213141516样例input3aaabababcoutput1abcinput3abcoutput0code:123456789101112131415161718192021222324252627282930313233343536373839#include<iostream>#include<cstring>#include<algorithm>#include<cmath>using namespace std;const int maxx=1e5;int main(){ string str[maxx], str2[maxx]; int n; cin >> n; for(int i = 1; i <= n; i ++) { cin >> str[i]; } int ans = 0, len = 1; for(int i = 1; i <= n; i ++) { int flag = 0;// if(str[i][0] == str[i][str[i].size() - 1]) continue; for(int j = 1; j <= n; j ++) { if(str[j][0] == str[i][str[i].size() - 1]) { flag = 1; break; } } if(flag) continue; ans ++; str2[len ++] = str[i]; } cout << ans << endl; for(int i = 1; i <= len; i ++) cout << str2[i] << endl; return 0;}大树的水塘Description:那一天,世界上所有的人类都……变成了石头!3700年后,千空和大树从石头中苏醒过来,但是世界发生了翻天覆地的变化,人类文明已经不复存在天才少年千空立志用自己的科学知识在这个「石之世界」中重建文明为了生存,淡水是必不可少的,每次都用海水进行蒸馏会比较麻烦,所以千空决定让大树建造一个水塘来存储雨水水塘建造在一个无限长,高度不超过100,宽度为1的峡谷里,所以只需要往里面填石头,即可达到蓄水的目的当大树建造好水塘让千空去检查的时候,千空一口老血喷了出来:因为大树是一个体力笨蛋,所以建造的水塘底部是参差不齐的,这使得建造蓄水相同体积的水塘,大树多用了好多石头已知每块石头中的规格是1×1×1,水塘的长度为N,宽度为1,在第i位置,大树放了ai个石头设大树建造的水塘蓄水量为V请你求出在长度和宽度不变的情况下,建造一个蓄水量不小于V的水塘最多可以节约多少石头输入格式单组输入第一行一个数N (1≤N≤10^7)表示水塘的长度第二行有N个非负数xi (0≤xi≤100),表示第i个位置上放的石头数输出格式输出有两行第一行输出大树建造的水塘的蓄水量V第二行输出最多可以节约多少石头提示:1234567样例input52 1 3 1 3output38code:12345678910111213141516171819202122232425262728293031323334353637#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxx = 1e7 + 10;int a[maxx];int l[maxx], r[maxx];int main(){ ios::sync_with_stdio(false); cin.tie(0); int n; int max_left, max_right; int cnt_left, cnt_right; ll v; cin >> n; ll sum = 0; for(int i = 0; i < n; i ++) //输入每个石块,算出总石头个数 cin >> a[i], sum += 1LL * a[i]; max_left = max_right = 0; v = 0; //前后缀 for(int i = 0; i < n; i ++) max_left = max(max_left, a[i]), l[i] += max_left; for(int i = n - 1; i >= 0; i --) max_right = max(max_right, a[i]), r[i] += max_right; //利用前后缀和的优势找出来,算出储水体积 for(int i = 0; i <= n; i ++) v += 1LL * min(l[i], r[i]) - a[i]; cout << v << "\n"; //除去两边的石块(因为两边都是石头) int height = ceil(1.0 * v / (n - 2)); //保证储水不溢出,两边都要有防护 cout << sum - height * 2 << "\n"; return 0;}幸运素数Description:跳皮筋 我第一,马兰开花二十一;二五六 二五七,二八二九三十一;三五六 三五七,三八三九四十一;……童谣《马兰花》作为建国以来最大的数学难题,里面数字的含义困扰了全国人民几十年,并且一直未解难道这些数字真的只是为了押韵生搬硬凑的数字吗?并!不!是!经过wzy的多年研究,他发现了里面潜藏的惊天大秘密(并没有):28=256,而257是离256最近的素数28是第二个完美数,29是离28最近的素数31是第四个幸运素数仅仅这一句话中,就出现了二进制、素数、完美数、幸运数!这哪里是童谣?这分明就是中国版的达芬奇密码!今天wzy就来考考你《马兰花》里出现的数学知识:幸运数是经由类似埃拉托斯特尼筛法的演算法后留下的整数集合,是在1955年波兰数学家乌拉姆提出。由一组由1开始的数列为例: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, …先将所有偶数删去,只留下奇数:1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25,…然后把数列中的第 2 个数字(设该数字为 x )的倍数对应的数删除,即把所有第 nx,x∈Z+ 个数删除,例如上述例子中,第 2 数字是 3 ,所以删去所有第 3n 个数:1, 3, 7, 9, 13, 15, 19, 21, 25,…新数列的第 3 项(每次都加上 1 )为 7 ,因此将新数列的第 7n 个数删除:1, 3, 7, 9, 13, 15, 21, 25,…若一直重复上述的步骤,最后剩下的数就是幸运数(以上内容来自维基百科幸运数)我们将既是幸运数又是素数的数叫做幸运素数现在给你一个数N,请判断N是否是一个幸运素数输入格式第一行一个数T,代表有T个数(1≤T≤2×10^5)第1∼T行,每行一个正整数N(1≤N≤2×10^5)输出格式对于每个输入的数N,如果N是幸运素数,输出Yes,否则输出No12345678910样例input3123outputNoNoYescode:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960#include<bits/stdc++.h>using namespace std;const int maxx = 2e5 + 50;int prime[maxx], luck[maxx];vector<int> v;void get_prime(){ for(int i = 1; i < 200010; i ++) prime[i] = 1; prime[0] = prime[1] = 0; for(int i = 2; i < 200010; i ++) { for(int j = 2; j * i < 200010; j ++) prime[i * j] = 0; }}void get_luck(){ v.push_back(0); for(int i = 1; i < 200010; i += 2) v.push_back(i); for(int i = 1; i < 200010; i ++) luck[i] = 0; int ti = 2; while(true) { int len = v.size(); int s = v[ti]; if(s > len - 1) break; for(int i = s; i < len; i += s) v[i] = 0; for(auto it = v.begin() + 1; it < v.end(); it ++) if(*it == 0) v.erase(it); ti ++; } for(int i = 1; i < v.size(); i ++) luck[v[i]] = 1;}int main(){ get_prime(); get_luck(); int t , n; scanf("%d",&t); for(int i = 1; i <= t; i ++) { scanf("%d",&n); if(luck[n] && prime[n]) printf("Yes\n"); else printf("No\n"); } return 0;}NO GAME NO LIFEDescription:空白,永不败北!作为世界的唯一神灵,游戏之神特图的日常就是改变自己的外表,在世界各地游荡在被空和白在一次网上的国际象棋比赛击败后,他以拯救人类种的名义将兄妹二人召唤到迪斯博德来到迪斯博德的空白,常常因为在游戏上找不到对手而感到无聊在风和日丽的一个下午,空白出门视察国情,在路上偶遇了扮成人类种闲逛的特图,特图为了打发时间,决定向空白发起挑战,游戏内容如下:在一棵有着N个节点的树上,第i个节点上有xi颗钻石,由最先开始的一方选择一个节点进行标记,标记完成后,双方轮流进行如下操作:拿走标记节点的一颗钻石,并将标记移至与当前节点直接相连的节点,至到出现无法拿石子的一方停止。空白兄妹听完游戏规则后,立刻做出了回应,但前提是空白作为先手选择节点特图自认为这是一个特别公平的游戏,所以就答应了这个要求每当一棵树出现后,空白凭借超人的数学能力,能够在一秒内快速判断出能否获胜输入格式单组输入,第一行一个正整数N (2≤N≤10^6),表示这棵树有N个节点第二行有N个正整数xi (1≤xi≤100),表示i节点上有xi颗钻石接下来N−1行,每行两个整数x,y (1≤x,y≤N),表示节点x与节点y相连输出格式如果空白可以获胜,输出Blank否则输出Teto12345678910111213样例input21 11 2outputTetoinput21 21 2outputBlankcode:12345678910111213141516171819202122232425#include<bits/stdc++.h>using namespace std;const int maxx = 1e6 + 10;int a[maxx];int main(){ ios::sync_with_stdio(false); cin.tie(0); int n; cin >> n; for(int i = 0; i < n; i ++) cin >> a[i]; int x, y; for(int i = 1; i < n; i ++) cin >> x >> y; sort(a, a + n); n = unique(a, a + n) - a; if(n == 1) cout<<"Teto"<<endl; else cout<<"Blank"<<endl; return 0;}/*不要直接用cin,cout,会超时*/]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day21]]></title>
<url>%2F2019%2F08%2F09%2FDay21%2F</url>
<content type="text"><![CDATA[Day21今天讲的是强连通量中间插入了一场比赛补题简介有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量(strongly connected components)。比赛链接题解Equivalent SetsDescription:To prove two sets A and B are equivalent, we can first prove A is a subset of B, and then prove B is a subset of A, so finally we got that these two sets are equivalent.You are to prove N sets are equivalent, using the method above: in each step you can prove a set X is a subset of another set Y, and there are also some sets that are already proven to be subsets of some other sets.Now you want to know the minimum steps needed to get the problem proved.InputThe input file contains multiple test cases, in each case, the first line contains two integers N <= 20000 and M <= 50000.Next M lines, each line contains two integers X, Y, means set X in a subset of set Y.OutputFor each case, output a single integer: the minimum steps needed.1234567891011Sample Input4 03 21 21 3Sample Output42HintCase 2: First prove set 2 is a subset of set 1 and then prove set 3 is a subset of set 1.题解:对于这样一个题目,很容易就可以把子集关系转换成有向图的一条有向边,那么题目就转换为求最少增加多少条有向边使得该图成为一个强连通图.对于一个图来说,他内部可能存在许多强连通分量,对于这些强连通分量之间,他们是不需要再进行建边了,我们可以将一个个强连通分量缩成一个个点,那么我们只需要让这些缩点后的图(有向无环图)是一个强连通图即可.这里用到一点贪心的思想:对于一个有向无环图,若有zin个入度为0的点,我们最多只需要增加zin条有向边,若是有zout个出度为0的点,我只需要增加zout条有向边,那么对于一个有向无环图要成为一个强连通图,我们最少只需要增加max(zin,zout)条有向边即可.code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128#include<iostream>#include<algorithm>#include<cstdio>#include<cmath>#include<string>#include<cstring>#include<map>#include<vector>using namespace std;#define ll long longconst int maxn = 20005;struct Tarjan { int n; //点的个数 vector<int>e[maxn]; //邻接表存图 int DFN[maxn], LOW[maxn]; int index; //编辑计数器 int stk[maxn]; //栈 bool ins[maxn]; //记录点是否在栈中 int top; vector<vector<int> >ans; void init(int N) { //初始化 n = N; ans.clear(); for (int i = 1; i <= n; i++) e[i].clear(); top = 0; index = 0; memset(DFN, -1, sizeof(DFN)); memset(ins, 0, sizeof(ins)); } void add_edge(int u, int v) {//添加边 e[u].push_back(v); } void dfs(int u) { //从u点开始搜索 DFN[u] = LOW[u] = ++index; stk[top++] = u; //为了记录这个连通分量中的节点 ins[u] = true; for (int i = 0; i < e[u].size(); i++) { int v = e[u][i]; if (DFN[v] == -1) { dfs(v); LOW[u] = min(LOW[u], LOW[v]); } else if (ins[v]) LOW[u] = min(LOW[u], DFN[v]); } if (DFN[u] == LOW[u]) { //当DFN==LOW时说明stk中点可以形成一个强连通分量 vector<int>q; int v = stk[top - 1]; while (u != v) { q.push_back(v); ins[v] = false; top--; v = stk[top - 1]; } q.push_back(u); ins[u] = false; top--; ans.push_back(q); } } void solve() { //运行该函数后产生答案 for (int i = 1; i <= n; i++) if (DFN[i] == -1) dfs(i); }}T;int num[maxn];bool vis[maxn];vector<int> e[maxn]; //存强连通缩点后的得到的新图int n, m;int main(){ while (~scanf("%d%d",&n,&m)){ int u, v; T.init(n); //初始化 while(m--){ //建有向图 scanf("%d%d", &u, &v); T.add_edge(v, u); //这里是u->v } T.solve(); //获得该有向图的所有强连通分量 for (int i = 1; i<=n; i++) //清空新图 e[i].clear(); //缩点 for (int i = 0; i< T.ans.size(); i++) for (int j = 0; j< T.ans[i].size(); j++) num[T.ans[i][j]] = i + 1; /* for(int i=1;i<=n;i++) //输出缩点情况 printf("%d:%d\n",i,num[i]); */ for (int i = 1; i<=n; i++) //建新有向无环图 for (int j = 0; j < T.e[i].size(); j++) { if (num[i] == num[T.e[i][j]]) continue; e[num[i]].push_back(num[T.e[i][j]]); //printf("%d->%d\n",num[i],num[T.e[i][j]]);输出图 } n = T.ans.size(); //新图的点数 //以上为Tarjan算法的强连通缩点操作,得到新的有向无环图为e[],点数为n memset(vis, 0, sizeof(vis)); int zin = 0, zout = 0; //分别为入度为0的点数和出度为0的点数 for (int i = 1; i <= n; i++){ if (e[i].size() == 0)zout++; for (int j = 0; j < e[i].size(); j++) vis[e[i][j]] = true; } for(int i=1;i<=n;i++) if (!vis[i])zin++; if (n != 1)printf("%d\n", max(zin, zout)); else printf("0\n"); //若是只有一点点需要特判结果为0,否则输出1 } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
<tag>图论</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day21比赛题解]]></title>
<url>%2F2019%2F08%2F09%2FDay21%E9%A2%98%E8%A7%A3%2F</url>
<content type="text"><![CDATA[Day21比赛题解补题PS:只要能看得懂题意,就是水题了链接MaratonIME helps PablitoDescription:♬ Caloventor tiene miedo… ♬Benedetto, NathanAs is well known by any cultured person, rats are the smartest beings on earth. Followed directly by dolphins.MaratonIME knows about the species hierarchy and uses this knowledge in it’s regard. Usually, when they need some resource, they know it’s always useful to have a smart rat available. Unfortunately, rats are not very fond of us, primates, and will only help us if they owe us some favour.With that in mind, MaratonIME decided to help a little rat called Pablito. Pablito is studying rat’s genealogy, to help with cloning and genetic mapping. luckily, the way rats identify themselves make the job much easier.The rat society is, historically, matriarchal. At first, there were little families, each of which had it’s own leading matriarch. At that time, it was decided that rats would organize themselves according to the following rules:Each martiarch had an id number greater than one.Each of these ids were chosen in a way such that they would have the least amount of divisors possible.Each family member had the same id as the matriarch.The id of any newborn rat would be the product of its parents id’s.For instance, the offspring of a rat with id 6 and another with id 7 is 42.Pablito needs to know if two given rats have a common ancestor, but his only tool is the id number of each of the two rats, which is always a positive integer greater than 1 with no more than 16 digits. Can you help him?Create a program that decides if a pair of rats have some common ancestor.InputThe input begins with a positive integer t ≤ 105, the number of test cases.After that, follows t lines, each with two integers ai e bi identifying two rats.Every rat’s id is a positive integer greater than 1 and with no more than 16 digits.OutputFor each test case, print “Sim” if the rats ai and bi share a common ancestor and “Nao” otherwise.12345678ExampleInput22 43 5OutputSimNaocode:123456789101112131415161718192021#include<bits/stdc++.h>using namespace std;const int mod = 1e9;const int maxx = 1e5;int main(){ long long t, n, m; while(~scanf("%lld",&t)) { for(int i = 1; i <= t; i ++) { scanf("%lld %lld",&n, &m); int ans = __gcd(n, m); if(ans != 1) puts("Sim"); else puts("Nao"); } } return 0;}MaratonIME plays CîrokimeDescription:Have you ever seen flavored vodka?Everaldo, GlauberThe MaratonIME members like to have fun. As they enjoy having fun so much, they have invented a game named “Cîrokime”. The game works as follows:First, n cups with Cîroc1 are lined up. In front of the i-th cup a number ai is written. It is guaranteed that ai < ai + 1, for all 1 ≤ i < n. Then, the numbers are covered and the game starts.The player must then find the cup that has a certain number x. It is guaranteed that this cup exists. For this, he has to choose a cup i and drink the beverage. Then, the cup’s number ai is revealed and if this number is equal to x the game finished. Otherwise, the player has to choose another cup and so on.“Cîrokime” is a traditional game among MaratonIME members, they play it every party. At the last party, Sussu had to drink all of the n cups because he found the right cup only at the end. He got sick for drinking so much and had to be carried home3However, the DESMAME4 is scheduled for May 13 and Sussu wants to restore his dignity. For this, he wants to know, in the worst case, what is the maximum number of cups that he will have to drink if he plays in the optimal way.InputThe first line has a single integer n, the number of cups. The second line has n integers ai, the values hidden in each cup.1 ≤ n ≤ 105For all i, 1 ≤ ai ≤ 109For i < n, ai < ai + 1OutputThe output has a single line with a single integer: the minimum number of cups that Sussu should drink, in the worst case, if he plays in the optimal way.1234567891011ExamplesInput32 5 7Output2Input81 2 3 4 5 6 7 8Output4code:123456789101112131415161718192021222324#include<bits/stdc++.h>using namespace std;const int mod = 1e9;const int maxx = 1e5;int a[maxx];int main(){ int t, ans; while(~scanf("%d",&t)) { memset(a, 0, sizeof a); ans = 0; for(int i = 0; i < t; i ++) cin >> a[i]; while(t) { t /= 2; ans ++; } printf("%d\n",ans); } return 0;}MaratonIME plays NimDescription:Ai Fox!UnionFind, GermanoYou open your eyes, but everything remains dark. The world is dark, and everything shakes. You realize you are locked in, but before desperation takes hold, you hear the door opening and the light invades your sight and blinds you for a few moments.They help you out, you had been locked inside a trunk. You don’t know the masked faces before you, but remember that in the last competitive programming practice they told you that “the beginning is yet to come”. “So this is the fabled MaratonIME’s initiation challenge”, you had heard rumors of this event, and you feel honored to be chosen.After walking into and abandoned building, they sit you on an old chair. The first test is to watch a soccer game without any show of excitement. Easy. The second is to install Linux on a notebook in less than 5 minutes. You were prepared, carrying the Arch Linux pendrive as usual, just in case. You face more tests, and manage to pass all of them despite a few difficulties.Hours go by, the members remove their masks, and each take a coin out of their pocket. “I won! And I even got rich” you think, but realize they place the coins in a table in front of you, divided in two piles. Renzo, MaratonIME’s great boss, takes a chair and sits in front of you. You will play a match of Nim, and if you win you will become an honorary member of MaratonIME, that is, you win a balloon.Nim is a game of two players, alternating their turns. Two piles of coins are placed on a table and in each turn you can remove any non zero quantity of coins from one of the piles. The last player to take their turn (leaving both piles empty) wins.You start the game. So it would not be unfair, it is guaranteed that it is possible for you to win. Write a program than beats Renzo 100% of the time.InputIn the first line, two integers, x and y, the size of the piles, such that 0 ≤ x, y ≤ 104. It is guaranteed that you can win the game.InteractionIn your turn, print two integers, i and x, where i is the number of the pile from which you will remove the coins (i 属于 {1, 2}), and x is the number of coins you will remove (x ≥ 1, such that i has at least x coins).In Renzo’s turn, read two integers, in the same format as in your turn.12345678910111213ExampleInput2 11 1Output1 12 1NoteOf course we do not do an initiation challenge like this :PIn the example, we have a pile with 2 coins and another with 1. You remove 1 coin from the first pile, and now no matter what coin Renzo removes, you can remove the other and win.Remember, after printing your play, flush the output, like: fflush(stdout); in C, cout.flush(); in C++, or sys.stdout.flush() in Python.关于flush()flush() 是把缓冲区的数据强行输出,(注意不要和frush()刷新混淆了)主要用在IO中,即清空缓冲区数据,一般在读写流(stream)的时候,数据是先被读到了内存中,再把数据写到文件中,当你数据读完的时候不代表你的数据已经写完了,因为还有一部分有可能会留在内存这个缓冲区中。这时候如果你调用了close()方法关闭了读写流,那么这部分数据就会丢失,所以应该在关闭读写流之前先flush()。code:12345678910111213141516171819202122232425262728293031323334353637#include<iostream>using namespace std;int main( ){ int a,b; cin>>a>>b; if(a==0) { cout<<2<<" "<<b<<endl; cout.flush(); return 0; } if(b==0) { cout<<1<<" "<<a<<endl; cout.flush(); return 0; } if(a>b) { cout<<"1"<<" "<<a-b<<endl; cout.flush(); } else if(a<b) { cout<<"2"<<" "<<b-a<<endl; cout.flush(); } int x; while(cin>>x>>b) { cout<<3-x<<" "<<b<<endl; cout.flush(); } return 0;}MaratonIME plays ChessDescription:This problem is boring as duck.Kawakami, MarcosOur dear Nathan, when a little child, used to like chess a lot, but this was a long time ago. One of these days he was challenged by @luisgust to a chess match and, as he is a guy that likes hard challenges, he accepted it. The problem is that Nathan keeps forgetting the rules of the game, so he asked you to help him determine if a given opponent’s piece can be captured in one move.Chess, in MaratonIME, is represented as a matrix of characters. Instead of playing with black and white pieces, they play with uppercase and lowercase letters. Nathan has chosen to play with the lowercase letters.Besides that, as usual, the positions on the matrix are given in the following coordinates system: Each position is a pair with a character between a and h (inclusive), representing the column, and an integer between 1 and 8 (inclusive), representing the row. For exemple, the position d2 refers to the fourth column (from left to right) and second row (from bottom to top), and the position f6 refers to the sixth column and sixth row. Lowercase letters start on the bottom of the grid, on lines 1 and 2.Here position A is adjacent position B if A shares a vertex with B, that is, if the distance between their rows is at most one and the distance between their columns is at most one. For example, the position c4 is adjacent to 8 positions: b3, b4, b5, c3, c5, d3, d4 and d5.They decided to play a simplified version of chess. To help you, they gave you the following manual on how to play it:The pawn, represented by p or P, can capture pieces that share a diagonal and is in front of it, that is, the lowercase pawn on c4 can capture pieces at b5 or d5.The knight, represented by c or C, makes L-shaped moves in any of the 8 possible directions, that is, it moves two positions in any direction and after that one position in a direction that is perpenticular to the first one. A knight on c4 can capture, in one move, pieces on positions a3, a5, b2, b6, d2, d6, e3 and e5.The rook, represented by t or T, can capture pieces that are on the same row or the same column as it, as long as no other piece lies between them. For example, a rook on c4 can capture any piece on column c or row 4, as long as there is no other piece in between. If the rook is on c4 and there is another piece on c6, the rook can’t capture pieces on c7 and c8.The bishop, represented by b or B, can capture any piece on one of its diagonals as long as there are no piece between them (diagonaly). For example, the bishop on c4 can capture a piece on f7 as long as there are no piece on d5 and e6.The queen, represented by r or R, can capture any piece that lies on the same row, column or diagonal, given there are no pieces in between, as if it were a bishop and a rook at the same time.The king, represented by k or K, can capture any piece that is adjacent to it.The character . represents an empty position.Given a matrix representing a chess board and an opponent’s piece, your program needs to determine whether you can capture it with one of your pieces. It is guaranteed that each player has at most two bishops, two rooks, two knights, eight pawns, one king and one queen.InputThe input begins with 8 lines with 8 characters each, representing the chess board. The first line contains the characters on the positions a8, b8, … , h8. The second line contains the characters on positions a7, b7, … , h7, and so on. After that follows a line containing the position of the opponent’s piece you wish to capture.OutputPrint a single line containing the word Sim if it is possible to capture the piece or Nao otherwise.12345678910111213141516171819202122232425ExamplesInputTCBRKBCTPPPPPPPP................................pppppppptcbrkbctd8OutputNaoInput..........................R........p............................c5OutputSimcode:1不会,,,MaratonIME rides the university busDescription:If we organize it correctly, …UnknownTo make the trip to the subway less boring and tiring, the SPSU, Sao Paulo State University, tried one of its most famous inventions: buses with Infinite Inner Length! In such a modern engineering wonder, there’s always a couple of empty seats for the students to sit and chat during the trip.MaratonIME crew is very popular, so popular that they have friends at every SPSU institute. Like everyone else from this university, they need to take the bus after a long day learning how to fix the Wi-Fi network. Because they don’t practice sports like rowing, every SPSU student sits right after entering the bus, making pairs whenever possible. Thinking about that, Gi, an ICPC expert, comes with a problem to think on the way to the subway: given a number n which indicates the number of institutes at SPSU and n integers ai representing the amount of people waiting for the bus at the institute i, Gi wants to know for m pairs lj, rj (lj ≤ rj) if all the people waiting for the bus at any point between lj e rj (inclusive) took an empty bus, they could sit together in pairs (nobody would sit alone).InputThe input consist in one line with two integers n and m, the number of institutes and the number of Gi’s questions. In the second line there are n integers ai, the number of people waiting for the bus at the ith institute. Then follows m lines with two integers each, li and ri, the first and last institute of Gi’s question.1 ≤ n, m ≤ 1050 ≤ ai ≤ 1051 ≤ li ≤ ri ≤ nOutputOutput “Sim” if it is possible to organize all the pairs in a way nobody sits alone or “Nao” otherwise.1234567891011ExampleInput5 21 4 10 3 23 52 3OutputNaoSimNoteIn the first sample we have 5 institutes with 1, 4, 10, 3 and 2 students. Gi asks if it is possible to form only couples if the ones between the 3rd and the 5th institutes takes an empty bus and the ones between the 2nd and the 3rd. For the first we have 15 so we can't and for the second we have 14 so we can.code:123456789101112131415161718192021222324252627282930#include<bits/stdc++.h>using namespace std;const int mod = 1e9;const int maxx = 1e5;int a[maxx];int main(){ int n, m; int sum[maxx]; while(~scanf("%d %d",&n, &m)) { memset(sum, 0, sizeof sum); memset(a, 0, sizeof a); for(int i = 1; i <= n; i ++) { cin >> a[i]; sum[i] += sum[i - 1] + a[i]; } int x, y; for(int i = 1; i <= m; i ++) { scanf("%d %d",&x, &y); if((sum[y] - sum[x - 1]) & 1) puts("Nao"); else puts("Sim"); } } return 0;}MaratonIME attends the lecture (or not)Description:Has the prof taken attendance yet?Student, IME’sIn MaratonIME, as many other groups, some students want to attend lectures just enough to not be flunked by frequency (as we know, in USP, University of Sao Paulo, it is necessary to have 70 percent frequency), however some others are dedicated and try to accomplish the most frequency percent possible, going to school even when they are ill or tired. Curiously, there is not any other kind of students in MaratonIME.Wood, an old MaratonIME’s member, needs help. He is taking the course MAC4815162342, and attended k of m lectures that were given. Consider that MAC4815162342 has n lectures in total per semester. He ask you to help finding the best way to accomplish his objectives, but, as you are new in MaratonIME, you don’t know the kind of student that he is. Embarassed to ask more, you decide to solve two problems, so there is not way to go wrong.InputThe input consists of a just one line. In this line, you are given three integers n, m and k, with 1 ≤ n ≤ 107 and 0 ≤ k ≤ m ≤ n.n is the number of lectures of MAC4815162342 per semester, m is the quantity of lectures that were given and k is the number of lectures attended by Wood.OutputIn the first line, print the minimum number of lectures that Wood needs to attend to accomplish at least 70% frequency, or - 1 if it is impossible to accomplish 70% frequency.In the second line, print the maximum frequency percent that Wood can accomplish, if he goes to all of the lectures from the next lecture. This value has to be rounded down to the closest integer. Don’t print ‘%’.12345678910111213ExamplesInput10 5 2Output570Input11 2 1Output790NoteOn the second example, the maximum percentage that Wood can get is 90.9090.code:12345678910111213141516#include<bits/stdc++.h>using namespace std;int main(){ int n, m, k, ans; while(~scanf("%d %d %d",&n, &m, &k)) { int x = (ceil)(0.7 * n); if(x > k) x -= k; else x = 0; ans = (k + n - m) * 100.0 / n; if(ans < 70) x = -1; printf("%d\n%d\n",x, ans); } return 0;}MaratonIME goes rowingDescription:Speed down, Colombooo!!!rowing coach, GabiAs common sense tells us, competitive programmers excel at rowing. The olympic lane is a wonderful place to row, run and work out. What few take their time to appreciate are the capybaras that inhabit the region. Capybaras are fascinating animals! Aside from their beauty, they possess many interesting behaviours. Did you know that capybaras can live in packs as big as 100 individuals?In a pleasant sunny morning, Yan was running, as usual. Watching the capybaras, he noticed that they would line up to sunbath. Each capybara was paired with another one, and only another one. Two capybaras can be paired if and only if both see each other. A capybara sees everything in the direction it is looking.Curious, Yan decided to represent the capybaras by the letters A and B, where A indicates that the capybara is looking right, and B indicates that the capybara is looking left.For example, the sequence AABABB accurately represents capybaras sunbathing, because it is possible to pair every capybara according to the rules above. Yan was so fascinate by this that he slipped and felt into the water, messing his representations. He was able to recover some, but now they are all messed up with each other. Can you help him and find out if a given sequence represent capybaras sunbathing?InputEvery instance contains a sequence S of characters, composed only of ‘A’ and ‘B’ – Yan’s representation. You may assume that 1 ≤ |S| ≤ 105.OutputThe output should contain a single line. Print “Sim” if the sequence represents capybaras sunbathing, or “Nao” otherwise.12345ExampleInputAABABBOutputSimcode:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152#include<bits/stdc++.h>using namespace std;const int maxx = 1e5;int main(){ string str; while(cin >> str) { int flag = 0, cnt = 0, ans = 0, L = 0, R = 0; int len = str.size() - 1; if((len + 1) & 1) { flag = 1; } else { for(int i = 0; i <= len; i ++) { if(str[i] == 'A') L ++; if(str[i] == 'B') R ++; } if(L != R) { flag = 1; } for(int i = 0; i < str.size() / 2; i ++) { if(str[0] == 'B' || str[len] == 'A') { flag = 1; break; } if(str[i] == 'A') { cnt ++; } else if(str[i] == 'B') { ans ++; } if(cnt < ans) { flag = 1; break; } } } if(flag) puts("Nao"); else puts("Sim"); } return 0;}MaratonIME goes to the moviesDescription:Better than “Fifth Wave”in the World, EveryoneBelieve it if you can, studies show that we in MaratonIME live not only out of competitive programming.In a saturday, after taking part in a virtual contest, our heroes decide to enjoy the afternoon watching a movie session. But they didn’t choose any movie, but an n-D movie, that is, a movie with n dimensions.During a chase scene, the main character jumps over a chain in the parking lot. Of course this was done in a very athletic way, and for some reason that drove Yan, one of the competitive programmers, mad.“Hollywood makes everything seem easy, but jumping over a chain is really hard!”The rest of the crowd, after the movie, argued with Yan that the actor surely jumped over the chain, but Yan disagreed, saying that it was done by some camera trick or by special effects.To prove his point, he bought another ticket for the movie and this time he took highly precise measuring instruments to the session. Yan’s plan was to show that the distance from the actor’s foot to the floor was smaller than the distance from the chain to the floor, and that would prove that the actor didn’t actually jump over the chain.But math in n dimensions is hard. Everyone knows that distance in the 2D plane between two points (x0, y0) and (x1, y1) is given by the formulaMost people also know that distance between two points (x0, y0, z0) e (x1, y1, z1) in 3D space is given by the formulaBoth formulas describe the euclidean distance, in the 2 and 3 dimensional case. Your task is, given three points in an n dimensional space, tell if the the closest ones are the foot and the floor or the chain and the flooor, according to euclidean distance.InputThe input begins with an integer n, followed by three lines, each with the representation of a point in an n-dimensional space.Dimensions confuse us, humans, so you can assume that 1 ≤ n ≤ 105.The second line represents the coordinates of the floor, and contains n integers a1, …, an.The third line represents the coordinates of the foot of the main character, and contains n integers b1, …, bn.The fourth line represents the coordinates of the chain, and contains n integers c1, …, cn.The movie theather is not arbitrarily large, so you can assume that the absolute value of these coordinates are not greater than 104.OutputPrint who wins the argument, that is, print “Yan” if the distance between the floor and the foot is not greater than the distance between the floor and the chain, or “MaratonIME” otherwise.123456789101112131415ExamplesInput20 01 12 2OutputYanInput40 0 0 02 2 2 21 1 1 1OutputMaratonIMEcode:1234567891011121314151617181920212223242526272829#include<bits/stdc++.h>using namespace std;const int mod = 1e4;const int maxx = 1e6;int a[4][maxx];int main(){ int n; while(~scanf("%d",&n)) { for(int i = 1; i <= 3; i ++) { for(int j = 1; j <= n; j ++) { cin >> a[i][j]; } } double ans1 = 0, ans2 = 0; for(int i = 1; i <= n; i ++) { ans2 += pow(a[3][i] - a[1][i], 2); ans1 += pow(a[2][i] - a[1][i], 2); } if(sqrt(ans1) <= sqrt(ans2)) puts("Yan"); else puts("MaratonIME"); } return 0;}MaratonIME goes to a japanese restaurantDescription:Matsu?Member, MaratonIME’sNathan and Yan are very dedicated programmers. They apply their knowledge in algorithms in problems beyond the programming competitions themselves, optimizing even the most trivial every day things.Some question if they aren’t just crazy, and if it wouldn’t be better to just do what has to be done.Anyhow, eventually some conflicts happen when their approaches differ about what has to be done. That always happens when they decide to go to japanese restaurants.Everybody knows that the objective in an all-you-can eat it to try to eat many distinct kinds of food. Nathan and Yan differ in opinions on how to achieve that. Both competitors, when sitting to eat an asian delicacy, eat until nothing is left on their plates.The difference is that Yan, respecting the wisdom of the nipponic masters, eats in the order the food arrives, whereas Nathan claims that the food is better the latter it arrives, to spare the most expensive ingredients, and so asks that his plates come in inverted order.Given the default order the dishes will arrive and the time Nathan and Yan will stay at the restaurant, determine who is going to eat the most different kinds of food, or if both ate the same number of different kinds of food, given that Yan eats the food in order and Nathan in inverted order.InputThe first line of input has two integers: 0 < n ≤ 105, how many plates will be served and 0 < T ≤ 106, how long (in minutes) Yan and Nathan will stay at the restaurant.In the following line, n integers 0 < ti ≤ 103, ti is how long it takes to eat the i-th dish (in minutes).The restaurants are very well administrated, so you can assume that when one of the competitors finishes his dish, the following dish is already on the table.OutputIf Yan is going to taste more dishes than Nathan, print “Yan”. If Nathan is going to taste more dishes than Yan, print “Nathan”. Otherwise, if we have a tie, print “Empate”.1234567891011ExamplesInput10 451 2 3 4 5 6 7 8 9 10OutputYanInput10 4510 2 3 4 5 6 7 8 9 1OutputNathancode:123456789101112131415161718192021222324252627282930313233343536373839404142434445#include<bits/stdc++.h>using namespace std;const int mod = 1e9;const int maxx = 1e5 + 10;int a[maxx];int b[maxx];int main(){ int n, t; while(~scanf("%d %d",&n, &t)) { memset(a, 0, sizeof a); memset(b, 0, sizeof b); int sum = 0; int m = n; for(int i = 1; i <= n; i ++) { cin >> a[i]; sum += a[i]; b[m --] = a[i]; } int ans1 = 0, ans2 = 0; int t1, t2; t1 = t2 = t; if(sum >= t) { for(int i = 1; t1 >= 0; i ++) { t1 -= a[i]; ans1 ++; } for(int i = 1; t2 >= 0; i ++) { t2 -= b[i]; ans2 ++; } if(ans1 > ans2) puts("Yan"); else if(ans1 < ans2) puts("Nathan"); else puts("Empate"); } else puts("Empate"); } return 0;}MaratonIME goes to the japanese restaurant (again)Description:Nakato?from MaratonIME, MembersAfter a long day of hard training, MaratonIME (マラトニメ) members decided to go to a Japanese restaurant. Yeah, we love Japanese food.After a lot of sushi boats, when everyone was more than satisfied, they asked the sushi-man Sussushi (ススシ) for the last boat. Sussushi felt challenged and answered:– You want one more boat? You shall have one more boat…The sushi boat that he brought was the biggest that any contestant had ever seen. Some contestants even dare saying that was the biggest sushi boat that ever existed, exceeding the previous limit of 105 sushis made by the suhiwoman Gioza (ジョザ) in 742, in a festival for the king that year, Carlos-sama (カーロス様).Besides that the contestants accepted the challenge, and together they managed to eat all the sushis. After that, the contestants we’re so full that they couldn’t touch each other. They couldn’t even think about programming problems. Help them find what pair of friends are touching themselves, so they can move away from each other.The contestant are represented as circles in plane, and two contestants touch each other if the circles touch each other. It’s guaranteed that the intersection area of any two circles is null.InputIn the first line there is a single integer, n indicating the number of contestants (2 ≤ n ≤ 1000).Each one of the next n lines has 3 integers xi, yi e ri, the (i + 1)-th line describes the ith contestant. (xi, yi) are the coordinates of the center of the circle, and ri is the radius. ( - 104 ≤ xi, yi ≤ 104, 1 ≤ ri ≤ 2·104)It is guaranteed that the intersection area of any two circles is null.OutputFor each pair of circles that touch each other, print in one line the indexes of these circles. The collisions can be printed in any order, the indexes of both circles can also be printed in any order.Don’t print the collisions more than once, that means, if i intersects with j, print i j or j i, but not both.12345678ExampleInput30 0 25 0 310 10 1Output1 2code:123456789101112131415161718192021222324252627282930#include<bits/stdc++.h>using namespace std;const int mod = 1e9;const int maxx = 1e5;int a[maxx], b[maxx], c[maxx];int main(){ int n; while(~scanf("%d",&n)) { int x, y, z; for(int i = 1; i <= n; i ++) { cin >> a[i] >> b[i] >> c[i]; } for(int i = 1; i <= n; i ++) { for(int j = i + 1; j <= n; j ++) { x = pow(a[i] - a[j], 2); y = pow(b[i] - b[j], 2); z = pow(c[i] + c[j], 2); if(x + y <= z) cout << i << " " << j << endl; } } } return 0;}MaratonIME goes to the karaokeDescription:♬ Hit me, lock me up, do anything with me, … ♬and Marrone, BrunoAfter thousands of years repeating the title of this problem statement, always with an excited and inviting tone, Nathan finally persuaded his colleagues to go to the karaoke. He is feeling radiant with this achievement.But there is a problem. After so much time trying to make his friends go to the karaoke, Nathan is afraid of embarrassing himself when he goes to sing the following classics of Brazilian music:Waitress – Reginaldo RossiBlue Nightclub – Joaquim and ManuelPaper Heart – Sérgio KingsLove Bubble – FagnerYou did not teach me to forget – Fernando MendesTo avoid the humiliation, and to not discourage his fellows in future hang outs at the karaoke, Nathan decided to print all the song’s ciphers that are available in the karaoke, to check while he sings. However, this resulted in a colossal amount of paper, that he is not able to carry.But the perseverance and ingenuity of an envious programmer is not something you should underestimate.Nathan realized that, after all, there were only 7 musical notes. The specialists in this matter used to represent this notes with the letters A, B, C, D, E, F and G. Even more, it’s common that the same note appears several times in sequence. He decided then, to compress the songs, changing every occurrence of repeated notes with the note followed by how many times it occurs.For instance, given the sequence[(A,A,A,B,B,B,C,G,G,G,G,G,G,G,G,G,G,G)] the compressed version is [A3B3C1G11]Unfortunately, Nathan also needs to pack his floral suit and to comb his beard – two homeric jobs – and he is out of time to compress the notes. Help him to not embarrass himself by writing a program that can solve this task.InputEach input consist of a single line, a sequence of caracteres S such as |S| ≤ 105, formed only by the letters A, B, C, D, E, F and G.OutputFor each input, print in a single line, such as each sequence of similar notes are replaced by the note that occurs and how many times it occurs, as showed in the example.123456789ExamplesInputABBGAOutputA1B2G1A1InputAAABBBCGGGGGGGGGGGOutputA3B3C1G11code:123456789101112131415161718192021222324#include<bits/stdc++.h>using namespace std;const int mod = 1e9;const int maxx = 1e5;map<char, int> mp;int main(){ string str; while(cin >> str) { for(int i = 0; i < str.size(); i ++) { mp[str[i]] ++; if(str[i + 1] != str[i]) { printf("%c%d",str[i], mp[str[i]]); mp[str[i]] = 0; } } puts(""); } return 0;}MaratonIME goes kartingDescription:Yan, it’s red!!!desperate, PassengersOnce after a contest, the competitive programmers were sad because of bad results. Seeing the situation, Renzo, MaratonIME’s coach, suggested they should do something fun to relax. After a big discussion, they decided to go karting. Looking for a place that was viable to all students, they found Kartforces, a kart track near Cidade Universitária. However, the track was too small and only fitted two racers by race. As passionate competitive programmers, they organised a fair tournament where everyone raced against everyone, two by two, only once. In each race, the winner got one point on the scoreboard. Draws were allowed and no one scored in this case. The winner was the biggest scorer. There were N competitive programmers present and:Each competitive programmer had a skill hi.If hi > hj where 1 ≤ i, j ≤ N and i ≠ j, then the competitive programmer i won the race against j.You had access to the skills of all competitive programmers and now asks who was the champion.InputThe first line consists on a single integer N, the number of competitive programmers. The second line contains N integers hi, the skill of the i - th competitive programmer.1 ≤ N ≤ 1050 ≤ hi ≤ 109OutputThe output consists in a single integer i, the champion competitive programmer. If it’s not possible to determine the champion, print - 1.123456ExampleInput32 4 6Output3code:123456789101112131415161718192021222324252627282930313233343536#include<bits/stdc++.h>typedef long long ll;using namespace std;const ll mod = 1e9;const int maxx = 1e5 + 10;ll a[maxx];int main(){ int n; int ans, winner; int cnt; while(~scanf("%d",&n)) { memset(a, 0, sizeof a); winner = -1; for(int i = 1; i <= n; i ++) { scanf("%lld",&a[i]); if(a[i] > winner) { winner = a[i]; ans = i; cnt = 1; } else if(a[i] == winner) { cnt ++; } else continue; } if(cnt >= 2) puts("-1"); else printf("%d\n",ans); } return 0;}MaratonIME returns homeDescription:♬ Renzo, they’re calling. Renzo, pick up the phone ♬Ringtones, TopPopular among the most traditional coders, the Summer Camp is famous for its fancy parties. After each party all attendees must return to their homes, but the way back home is not always easy: mildly drunk coders walk weird and often find or lose money along the way. However, MaratonIME always has a sober member in the group, who assures no one will lose money, except when they are robbed.On its way back MaratonIME knows that they can call their coach, Renzo, who will pick them up immediately. Instead of doing that right after the party, they want to know what is the maximum amount of money they can carry back to their homes.Your task is to write a program that solves this problem. Consider the following facts:The city map can be seen as an N by M grid;Members of MaratonIME are initially at the top left corner, and start walking right, carrying no money;Whenever they reach the end of a row, they walk to the row below and start walking in the opposite direction (if they were walking right, they walk left the next row, and vice-versa);They cannot go past the last row;Whenever they meet a burglar, they lose all their money;They can call Renzo at anytime, and he will pick them up instantly.InputThe first line of the input contains two integers N and M (1 ≤ N, M ≤ 103), respectively, the number of rows and columns of the grid. Then follows N lines, each containing M characters, representing the city map. Each cell of the city map can be either:, meaning there is nothing at this cell of the grid;, meaning there is a coin worth 1 unit of money at this cell;, meaning there is a burglar at that cell.OutputThe output must contain a single integer: the maximum amount of money MaratonIME can carry back home.12345678910ExampleInput3 3__._._L._Output2NoteIn the example above, MaratonIME follows the following path: (1, 1) (1, 2) (1, 3) (2, 3) (2, 2) (2, 1) (3, 1) (3, 2) (3, 3). When they reach (2, 2) or (2, 1) they will have 2 coins, and that is the highest value they can get before calling Renzo.code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546#include<bits/stdc++.h>using namespace std;const int mod = 1e9;const int maxx = 1e5;int n, m;char s[1010][1010];int main(){ scanf("%d %d",&n, &m); for(int i = 0; i < n; i ++) { cin >> s[i]; } int ans = 0, tmp = 0; for(int i = 0; i < n; i ++) { if(i % 2 == 0) { for(int j = 0; j < m; j ++) { if(s[i][j] == 'L') { ans = max(ans, tmp); tmp = 0; } else if(s[i][j] == '.') tmp ++; } } else { for(int j = m - 1; j >= 0; j --) { if(s[i][j] == 'L') { ans = max(ans, tmp); tmp = 0; } else if(s[i][j] == '.') tmp ++; } } } cout << ans << endl; return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
<tag>图论</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day20]]></title>
<url>%2F2019%2F08%2F08%2FDay20%2F</url>
<content type="text"><![CDATA[Day20今天讲的是LCA(最近公共祖先)补题提醒自己一下,因为今天有事没有写完这些题目,所以大部分的题解和代码都是在网上找到的,希望以后自己可以把这部分题补上简介最近公共祖先简称LCA(Lowest Common Ancestor)。两个节点的最近公共祖先,就是这两个点的公共祖先里面,离根最远的那个。为了方便,我们记某点集S = v1, v2, …, vn 的最近公共祖先为LCA (v1, v2, …, vn) 或LCA (S)解决算法朴素算法倍增算法Tarjan 算法转换成 RMQ 问题求解树链剖分动态树虽然算法多,但是我现在只学了前三个算法生动的解释详情链接朴素算法我们首先预处理出来所有节点所在的深度,对于需要查询的两点u, v,我们假设深度较深的点为 u,将 u 上移至与 v 相同深度的位置,然后同时上移节点 u, v,直至两节点相遇,相遇的点即为LCA(u, v)最坏复杂度 O (N)倍增算法倍增算法求 LCA 就是利用倍增法对朴素算法的一个优化,预处理时间复杂度 O(nlogn)可以将查询的时间复杂度降到 O (logN)总的时间复杂度:O(nlogn + qlogn)加一个(假)模板12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576#pragma GCC optimize(2)//O2优化#include<bits/stdc++.h>using namespace std;const int N = 1000000;long long bit[N];int depth[N],f[N][30];vector<int> G[N];int Scan(){ // 输入外挂 int res = 0, flag = 0; char ch; if ((ch = getchar()) == '-') { flag = 1; } else if(ch >= '0' && ch <= '9') { res = ch - '0'; } while ((ch = getchar()) >= '0' && ch <= '9') { res = res * 10 + (ch - '0'); } return flag ? -res : res; } void init(){ bit[0]=1; for(int i=1;i<=29;i++) bit[i]=(bit[i-1]*2);}void dfs(int u,int par){ depth[u]=depth[par]+1; f[u][0]=par; for(int i=1;i<=29;i++) f[u][i]=f[f[u][i-1]][i-1]; for(int i=0;i<(int)G[u].size();i++){ int v=G[u][i]; if(v==par) continue; dfs(v,u); }}int lca(int a,int b){ if(depth[a]<depth[b]) swap(a,b); int dif=depth[a]-depth[b]; for(int i=29;i>=0;i--){ if(dif>=bit[i]){ a=f[a][i]; dif-=bit[i]; } } if(a==b) return a; for(int i=29;i>=0;i--){ if(depth[a]>=bit[i]&&f[a][i]!=f[b][i]){ a=f[a][i];b=f[b][i]; } } return f[a][0];}int main(){ init(); int n,m,s; n=Scan();m=Scan();s=Scan(); int u,v; for(int i=1;i<=n-1;i++){ u=Scan();v=Scan(); G[u].push_back(v); G[v].push_back(u); } dfs(s,0); while(m--){ u=Scan();v=Scan(); printf("%d\n",lca(u,v)); } return 0;}Tarjan算法Tarjan 算法是一种常见的用于解决 LCA 问题的离线算法,它结合了深度优先搜索与并查集,预处理时间复杂度 O(nlogn), 每次查询时间复杂度 O(1),总时间复杂度是 O(nlogn + q)。基础若两个结点 u, v 分别分布于某节点 T 的左右子树,那么此节点 t即为 u 和 v 的最近公共祖先。更进一步,考虑到一个节点自己就是 LCA 的情况,得知:若某结点 T 是两结点 u, v 的祖先之一,且这两结点并不分布于该结点 t 同一棵子树中,而是分别在结点 T 的左子树、右子树中,那么该结点 T 即为两结点 u, v 的最近公共祖先思路任选一个节点为根节点,从根节点开始遍历该点 u 的所有子节点 v 并标记 v 已经被访问过若 v 还有子节点,返回第二步,否则下一步合并 v 到 u 所在集合寻找与当前点 u 有询问关系的点 e若 e 已经被访问过,则可以确定 u, e 的最近公共祖先为 e被合并到的父亲节点代码1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556//并查集部分int find(int x){ if(x != f[x]) { f[x] = find(f[x]); } return f[x];}void join(int x, int y){ int dx = f[x], dy = f[y]; if(dx != dy) f[dy] = f[dx];}//存储查询关系struct Query{ int q, next; int index;}Q[maxx * 2];int h[maxx];int tt;void add_query(int u, int v, int index){ Q[tt].q = v; Q[tt].next = h[u]; Q[tt].index = index; h[u] = tt ++; Q[tt].q = u; Q[tt].next = h[v]; Q[tt].index = index; h[v] = tt ++; }//核心代码void lca(int u){ fa[u] = u; vis[u] = 1; for(int i = head[u]; i != -1; i = edge[i].next)//和顶点u相关的顶点 { int v = edge[i].to; if(vis[v]) continue; lca(v); join(u, v);//将u的左右孩子的祖先设为u fa[find(u)] = u; } //看输入的查询里面有没有和u节点相关的 for(int i = h[u]; i != -1; i = Q[i].next) { int v = Q[i].q; if(vis[v]) ans[Q[i].index] = fa[find(v)]; }}OJ链接Nearest Common AncestorsDescription:A rooted tree is a well-known data structure in computer science and engineering. An example is shown below:In the figure, each node is labeled with an integer from {1, 2,…,16}. Node 8 is the root of the tree. Node x is an ancestor of node y if node x is in the path between the root and node y. For example, node 4 is an ancestor of node 16. Node 10 is also an ancestor of node 16. As a matter of fact, nodes 8, 4, 10, and 16 are the ancestors of node 16. Remember that a node is an ancestor of itself. Nodes 8, 4, 6, and 7 are the ancestors of node 7. A node x is called a common ancestor of two different nodes y and z if node x is an ancestor of node y and an ancestor of node z. Thus, nodes 8 and 4 are the common ancestors of nodes 16 and 7. A node x is called the nearest common ancestor of nodes y and z if x is a common ancestor of y and z and nearest to y and z among their common ancestors. Hence, the nearest common ancestor of nodes 16 and 7 is node 4. Node 4 is nearer to nodes 16 and 7 than node 8 is.For other examples, the nearest common ancestor of nodes 2 and 3 is node 10, the nearest common ancestor of nodes 6 and 13 is node 8, and the nearest common ancestor of nodes 4 and 12 is node 4. In the last example, if y is an ancestor of z, then the nearest common ancestor of y and z is y.Write a program that finds the nearest common ancestor of two distinct nodes in a tree.InputThe input consists of T test cases. The number of test cases (T) is given in the first line of the input file. Each test case starts with a line containing an integer N , the number of nodes in a tree, 2<=N<=10,000. The nodes are labeled with integers 1, 2,…, N. Each of the next N -1 lines contains a pair of integers that represent an edge –the first integer is the parent node of the second integer. Note that a tree with N nodes has exactly N - 1 edges. The last line of each test case contains two distinct integers whose nearest common ancestor is to be computed.OutputPrint exactly one line for each test case. The line should contain the integer that is the nearest common ancestor.12345678910111213141516171819202122232425262728Sample Input2161 148 510 165 94 68 44 101 136 1510 116 710 216 38 116 1216 752 33 43 11 53 5Sample Output43code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394#include<iostream>#include<cstring>#include<vector>#include<stdio.h>using namespace std;typedef long long ll;const int maxx = 1e5;ll bits[maxx];//存节点int f[maxx][30];//存子节点int depth[maxx];//存储深度vector<int> v[maxx];int in[maxx];//初始化void init(){ bits[0] = 1; for(int i = 1; i <= 29; i ++) bits[i] = bits[i - 1] << 1;}//预处理void dfs(int u, int par){ depth[u] = depth[par] + 1; f[u][0] = par; //倍增 for(int i = 1; i <= 29; i ++) f[u][i] = f[f[u][i - 1]][i - 1]; for(int i = 0; i < v[u].size(); i ++) { if(v[u][i] == par) continue; dfs(v[u][i], u); }}//lcaint lca(int a, int b){ if(depth[a] < depth[b]) swap(a, b); int dis = depth[a] - depth[b]; for(int i = 29; i >= 0; i --) { if(dis >= bits[i]) { a = f[a][i]; dis -= bits[i]; } } if(a == b) return a; for(int i = 29; i >= 0; i --) { if(depth[a] >= bits[i] && f[a][i] != f[b][i]) { a = f[a][i]; b = f[b][i]; } } return f[a][0];}int main(){ init(); int t, n, x, y; scanf("%d",&t); while(t --) { memset(in, 0, sizeof in); for(int i = 1; i <= n; i ++) v[i].clear(); scanf("%d",&n); for(int i = 1; i <= n - 1; i ++) { scanf("%d %d",&x, &y); v[x].push_back(y); v[y].push_back(x); in[y] ++; } int root; scanf("%d %d",&x, &y); for(int i = 1; i <= n; i ++) { if(!in[i]) { root = i; break; } } dfs(root, 0); printf("%d\n",lca(x, y)); } return 0;}Distance QueriesDescription:Farmer John’s cows refused to run in his marathon since he chose a path much too long for their leisurely lifestyle. He therefore wants to find a path of a more reasonable length. The input to this problem consists of the same input as in “Navigation Nightmare”,followed by a line containing a single integer K, followed by K “distance queries”. Each distance query is a line of input containing two integers, giving the numbers of two farms between which FJ is interested in computing distance (measured in the length of the roads along the path between the two farms). Please answer FJ’s distance queries as quickly as possible!InputLines 1..1+M: Same format as “Navigation Nightmare”Line 2+M: A single integer, K. 1 <= K <= 10,000Lines 3+M..2+M+K: Each line corresponds to a distance query and contains the indices of two farms.OutputLines 1..K: For each distance query, output on a single line an integer giving the appropriate distance.123456789101112131415161718Sample Input7 61 6 13 E6 3 9 E3 5 7 S4 1 3 N2 4 20 W4 7 2 S31 61 42 6Sample Output13336HintFarms 2 and 6 are 20+3+13=36 apart.code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091#pragma GCC optimize(2)#include<iostream>#include<cstring>#include<vector>#include<stdio.h>using namespace std;typedef long long ll;const int maxx = 1e5;ll bits[maxx];//存节点int f[maxx][30];//存子节点int depth[maxx];//存储深度vector<pair<int, int> > v[maxx];int dis[maxx];//初始化void init(){ bits[0] = 1; for(int i = 1; i <= 29; i ++) bits[i] = bits[i - 1] << 1;}//预处理void dfs(int u, int par){ depth[u] = depth[par] + 1; f[u][0] = par; //倍增 for(int i = 1; i <= 29; i ++) f[u][i] = f[f[u][i - 1]][i - 1]; for(int i = 0; i < v[u].size(); i ++) { if(v[u][i].first == par) continue; dis[v[u][i].first] = dis[u] + v[u][i].second; dfs(v[u][i].first, u); }}//lcaint lca(int a, int b){ if(depth[a] < depth[b]) swap(a, b); int dis = depth[a] - depth[b]; for(int i = 29; i >= 0; i --) { if(dis >= bits[i]) { a = f[a][i]; dis -= bits[i]; } } if(a == b) return a; for(int i = 29; i >= 0; i --) { if(depth[a] >= bits[i] && f[a][i] != f[b][i]) { a = f[a][i]; b = f[b][i]; } } return f[a][0];}int main(){ init(); int t, n, m, k, x, y; char z[10]; while(~scanf("%d %d",&n, &m)) { memset(dis, 0, sizeof dis); for(int i = 1; i <= n; i ++) v[i].clear(); for(int i = 1; i <= n - 1; i ++) { scanf("%d %d %d %s",&x, &y, &k, &z); v[x].push_back(make_pair(y, k)); v[y].push_back(make_pair(x, k)); } dfs(1, 0); scanf("%d",&t); for(int i = 1; i <= t; i ++) { scanf("%d %d",&x, &y); int ans = lca(x, y), cnt = 0; cnt = dis[x] + dis[y] - 2 * dis[ans]; printf("%d\n",cnt); } } return 0;}Closest Common AncestorsDescription:Write a program that takes as input a rooted tree and a list of pairs of vertices. For each pair (u,v) the program determines the closest common ancestor of u and v in the tree. The closest common ancestor of two nodes u and v is the node w that is an ancestor of both u and v and has the greatest depth in the tree. A node can be its own ancestor (for example in Figure 1 the ancestors of node 2 are 2 and 5)The data set starts with the tree description, in the form:nr_of_verticesvertex:(nr_of_successors) successor1 successor2 … successorn……where vertices are represented as integers from 1 to n. The tree description is followed by a list of pairs of vertices, in the form:nr_of_pairs(u v) (x y) …The input contents several data sets (at least one).Note that white-spaces (tabs, spaces and line breaks) can be used freely in the input.For each common ancestor the program prints the ancestor and the number of pair for which it is an ancestor. The results are printed on the standard output on separate lines, in to the ascending order of the vertices, in the format: ancestor:timesFor example, for the following tree:the program input and output is:12345678910111213141516171819Input55:(3) 1 4 21:(0)4:(0)2:(1) 33:(0)6(1,5) (1,4) (4,2)(2,3)(1,3) (4,3)Output2:15:5code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<vector>using namespace std;typedef long long ll;const int N = 1e5;int f[N][30];int depth[N];int sum[N];int in[N];ll bits[30];vector<int> v[N];void init(){ bits[0] = 1; for(int i = 1; i <= 29; i ++) { bits[i] = bits[i - 1] << 1; }}//预处理void dfs(int u, int par){ depth[u] = depth[par] + 1; f[u][0] = par; for(int i = 1; i <= 29; i ++) f[u][i] = f[f[u][i - 1]][i - 1]; for(int i = 0; i < v[u].size(); i ++) { int V = v[u][i]; if(V == par) continue; dfs(V, u); }}int lca(int a, int b){ if(depth[a] < depth[b]) swap(a, b); int dis = depth[a] - depth[b]; for(int i = 29; i >= 0; i --) { if(dis >= bits[i]) { a = f[a][i]; dis -= bits[i]; } } if(a == b) return a; for(int i = 29; i >= 0; i --) { if(depth[a] >= bits[i] && f[a][i] != f[b][i]) { a = f[a][i]; b = f[b][i]; } } return f[a][0];}int main(){ init(); int a, b, n, m; while(~scanf("%d",&n)) { for(int i = 1; i <= n; i ++) v[i].clear(); memset(in, 0, sizeof in); for(int i = 0; i < n; i ++) { scanf("%d:(%d)",&a,&m); for(int j = 0; j < m; j ++) { scanf("%d",&b); v[a].push_back(b); v[b].push_back(a); in[b] ++; } // getchar(); } int ans; for(int i = 1; i <= n; i ++) { if(!in[i]) { ans = i; break; } } dfs(ans, 0); int t; scanf("%d",&t); memset(sum, 0, sizeof sum); for(int i = 0; i < t; i ++) { char c; while(scanf("%c",&c) && c != '('); scanf("%d,%d",&a, &b); while(scanf("%c",&c) && c != ')'); sum[lca(a, b)] ++; getchar(); } for(int i = 1; i <= n; i ++) { if(sum[i]) printf("%d:%d\n", i, sum[i]); } } return 0;}How far away ?Description:There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this “How far is it if I want to go from house A to house B”? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path(“simple” means you can’t visit a place twice) between every two houses. Yout task is to answer all these curious people.InputFirst line is a single integer T(T<=10), indicating the number of test cases.For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.OutputFor each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.1234567891011121314151617Sample Input23 21 2 103 1 151 22 32 21 2 1001 22 1Sample Output1025100100code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103#include<iostream>#include<cstring>#include<vector>#include<stdio.h>using namespace std;typedef long long ll;const int maxx = 1e5;ll bits[maxx];//存节点int f[maxx][30];//存子节点int depth[maxx];//存储深度vector<pair<int, int> > v[maxx];int in[maxx];int dis[maxx];//初始化void init(){ bits[0] = 1; for(int i = 1; i <= 29; i ++) bits[i] = bits[i - 1] << 1;}//预处理void dfs(int u, int par){ depth[u] = depth[par] + 1; f[u][0] = par; //倍增 for(int i = 1; i <= 29; i ++) f[u][i] = f[f[u][i - 1]][i - 1]; for(int i = 0; i < v[u].size(); i ++) { if(v[u][i].first == par) continue; dis[v[u][i].first] = dis[u] + v[u][i].second; dfs(v[u][i].first, u); }}//lcaint lca(int a, int b){ if(depth[a] < depth[b]) swap(a, b); int dis = depth[a] - depth[b]; for(int i = 29; i >= 0; i --) { if(dis >= bits[i]) { a = f[a][i]; dis -= bits[i]; } } if(a == b) return a; for(int i = 29; i >= 0; i --) { if(depth[a] >= bits[i] && f[a][i] != f[b][i]) { a = f[a][i]; b = f[b][i]; } } return f[a][0];}int main(){ init(); int t, n, m, k, x, y; scanf("%d",&t); while(t --) { memset(in, 0, sizeof in); memset(dis, 0, sizeof dis); for(int i = 1; i <= n; i ++) v[i].clear(); scanf("%d %d",&n, &m); for(int i = 1; i <= n - 1; i ++) { scanf("%d %d %d",&x, &y, &k); v[x].push_back(make_pair(y, k)); v[y].push_back(make_pair(x, k)); in[y] ++; } int r; for(int i = 1; i <= n; i ++) { if(!in[i]) { r = i; break; } } for(int i = 1; i <= m; i ++) { scanf("%d %d",&x, &y); dfs(r, 0); int ans = lca(x, y), cnt = 0; cnt = dis[x] + dis[y] - 2 * dis[ans]; printf("%d\n",cnt); } if(t != 0) puts(""); } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
<tag>图论</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day19]]></title>
<url>%2F2019%2F08%2F07%2FDay19%2F</url>
<content type="text"><![CDATA[Day19今天讲的是拓扑排序算法努力学习!!OJ链接加一个(假)模板12345678910111213141516171819202122232425262728293031323334353637383940414243444546#include<vector>#include<queue>#include<iostream>#include<cstring>using namespace std;int in[10100];// 存入度vector<int> v[10100];// 存关系 构建图int main(){ int m,n; int x,y; while(cin>>n>>m)// 根据题目要求可以改动 { memset(in,0,sizeof(in));// 清空入度 for(int i=1;i<=n;i++) v[i].clear() ;// 清空vector while(m--)// m组数据 { cin>>y>>x; in[y]++;// y的关系大于x,x指向y y的入度+1; v[x].push_back(y);// 就 y 放在 x后面 } queue<int>q;// 定义一个队列 最为节点的删除 for(int i=1;i<=n;i++) { if(!in[i]) { // 入度为零的节点放入 队列 q.push(i); } } while(!q.empty() ) { int xx=q.front() ; // 如果队列中一次存了大于 2 个节点 q.pop() ; //说明该图有 2->3 && 2->4 这种情况 有点个点之间没有关系 n--; // 总节点数 -1; for(int i=0;i<v[xx].size() ;i++) // 遍历这个节点后面的 点 { int yy=v[xx][i]; in[yy]--; // 删除 x 后 yy 的入度就 -1; if(!in[yy]) { // 如果此时 yy 入度为零放入队列 遍历他的下一个节点 q.push(yy); } } } if(n) cout<<"该图有环"<<endl; // 如果总结点数没减为零 说明有环的存在 } return 0;}Genealogical treeDescription:The system of Martians’ blood relations is confusing enough. Actually, Martians bud when they want and where they want. They gather together in different groups, so that a Martian can have one parent as well as ten. Nobody will be surprised by a hundred of children. Martians have got used to this and their style of life seems to them natural.And in the Planetary Council the confusing genealogical system leads to some embarrassment. There meet the worthiest of Martians, and therefore in order to offend nobody in all of the discussions it is used first to give the floor to the old Martians, than to the younger ones and only than to the most young childless assessors. However, the maintenance of this order really is not a trivial task. Not always Martian knows all of his parents (and there’s nothing to tell about his grandparents!). But if by a mistake first speak a grandson and only than his young appearing great-grandfather, this is a real scandal.Your task is to write a program, which would define once and for all, an order that would guarantee that every member of the Council takes the floor earlier than each of his descendants.InputThe first line of the standard input contains an only number N, 1 <= N <= 100 — a number of members of the Martian Planetary Council. According to the centuries-old tradition members of the Council are enumerated with the natural numbers from 1 up to N. Further, there are exactly N lines, moreover, the I-th line contains a list of I-th member’s children. The list of children is a sequence of serial numbers of children in a arbitrary order separated by spaces. The list of children may be empty. The list (even if it is empty) ends with 0.OutputThe standard output should contain in its only line a sequence of speakers’ numbers, separated by spaces. If several sequences satisfy the conditions of the problem, you are to write to the standard output any of them. At least one such sequence always exists.123456789Sample Input504 5 1 01 05 3 03 0Sample Output2 4 5 3 1code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364#include<iostream>#include<stdio.h>#include<cstring>#include<algorithm>#include<vector>#include<queue>using namespace std;const int mod = 1e9;const int maxx = 1e5;int in[maxx];vector<int> v[maxx];int main(){ int n, m, x, y; while(~scanf("%d",&n)) { //清空图 memset(in, 0, sizeof in); for(int i = 1; i <= n; i ++) { v[i].clear(); } //存图,找度数 for(int i = 1; i <= n; i ++) { for(int j = 1;; j ++) { scanf("%d",&x); if(x == 0) break; v[i].push_back(x); in[x] ++; } } priority_queue<int, vector<int>, greater<int> > q; //找到0入度,加入队列 for(int i = 1; i <= n; i ++) { if(in[i] == 0) q.push(i); } int flag = 1; while(!q.empty()) { int xx = q.top(); q.pop(); if(flag) { cout << xx; flag = 0; } else cout << " " << xx; for(int i = 0; i < v[xx].size(); i ++) { in[v[xx][i]] --; if(in[v[xx][i]] == 0) { q.push(v[xx][i]); } } } puts(""); } return 0;}Window PainsDescription:Boudreaux likes to multitask, especially when it comes to using his computer. Never satisfied with just running one application at a time, he usually runs nine applications, each in its own window. Due to limited screen real estate, he overlaps these windows and brings whatever window he currently needs to work with to the foreground. If his screen were a 4 x 4 grid of squares, each of Boudreaux’s windows would be represented by the following 2 x 2 windows:When Boudreaux brings a window to the foreground, all of its squares come to the top, overlapping any squares it shares with other windows. For example, if window 1 and then window 2 were brought to the foreground, the resulting representation would be:If window 4 were then brought to the foreground:. . . and so on . . .Unfortunately, Boudreaux’s computer is very unreliable and crashes often. He could easily tell if a crash occurred by looking at the windows and seeing a graphical representation that should not occur if windows were being brought to the foreground correctly. And this is where you come in . . .InputInput to this problem will consist of a (non-empty) series of up to 100 data sets. Each data set will be formatted according to the following description, and there will be no blank lines separating data sets.A single data set has 3 components:Start line - A single line:STARTScreen Shot - Four lines that represent the current graphical representation of the windows on Boudreaux’s screen. Each position in this 4 x 4 matrix will represent the current piece of window showing in each square. To make input easier, the list of numbers on each line will be delimited by a single space.End line - A single line:ENDAfter the last data set, there will be a single line:ENDOFINPUTNote that each piece of visible window will appear only in screen areas where the window could appear when brought to the front. For instance, a 1 can only appear in the top left quadrant.OutputFor each data set, there will be exactly one line of output. If there exists a sequence of bringing windows to the foreground that would result in the graphical representation of the windows on Boudreaux’s screen, the output will be a single line with the statement:THESE WINDOWS ARE CLEANOtherwise, the output will be a single line with the statement:THESE WINDOWS ARE BROKEN题意:给你一个44的棋盘窗口,现在电脑上有9个应用,每个应用占用固定的22正方形网格位置.你通过不同的顺序操作9个应用可以使得44的窗口当前显示的内容(数字代表)不同,现在给你一个44棋盘窗口的内容,问你这个内容是否合法.123456789101112131415161718Sample InputSTART1 2 3 34 5 6 67 8 9 97 8 9 9ENDSTART1 1 3 34 1 3 37 7 9 97 7 9 9ENDENDOFINPUTSample OutputTHESE WINDOWS ARE CLEANTHESE WINDOWS ARE BROKENcode:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172#include<cstdio>#include<cstring>#include<vector>#include<queue>using namespace std;const int maxn=10;vector<int> value[maxn][maxn];int dr[]={0,1,0,1};//原地,下,右,右下int dc[]={0,0,1,1};int G[maxn][maxn]; //图int in[maxn]; //入度bool topo(){ queue<int> Q; for(int i=0;i<9;i++) if(in[i]==0) Q.push(i); int sum=0;//记录我们删除的0入度点 while(!Q.empty()) { int u=Q.front(); Q.pop(); for(int v=0;v<9;v++)if(G[u][v]) { G[u][v]=0; if(--in[v]==0) Q.push(v); } sum++; } return sum==9;}int main(){ for(int i=0;i<9;i++) //处理0-8每个应用所在的方格vector { int r=i/3, c=i%3; //i应用左上角的格子所在的(r,c) for(int dir=0;dir<4;dir++) //i应用所在的其他3个点 { int nr=r+dr[dir], nc=c+dc[dir]; value[nr][nc].push_back(i); //将i压入对应方格的vector中 } } char str[100]; while(scanf("%s",str)==1&&str[0]!='E') { memset(G,0,sizeof(G)); memset(in,0,sizeof(in)); for(int i=0;i<4;i++) for(int j=0;j<4;j++) { int v; scanf("%d",&v); v--; for(int k=0;k<value[i][j].size();k++) if((value[i][j])[k]!=v)//构造有向边 { int x=(value[i][j])[k]; if(G[x][v]==0)//一定要做这个判断,因为会重复添加有向边 { in[v]++; G[x][v]=1; } //printf("当前格子为:(%d,%d),当前边为:%d v=%d, %d点的入度为%d\n",i,j,x,v,v,in[v]); } } if(topo()) printf("THESE WINDOWS ARE CLEAN\n"); else printf("THESE WINDOWS ARE BROKEN\n"); scanf("%s",str); } return 0;}确定比赛名次(拓扑排序)Description:有N个比赛队(1<=N<=500),编号依次为1,2,3,。。。。,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。Input输入有若干组,每组中的第一行为二个数N(1<=N<=500),M;其中N表示队伍的个数,M表示接着有M行的输入数据。接下来的M行数据中,每行也有两个整数P1,P2表示即P1队赢了P2队。Output给出一个符合要求的排名。输出时队伍号之间有空格,最后一名后面没有空格。其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。1234567Sample Input4 31 22 34 3Sample Output1 2 4 3code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556#include<bits/stdc++.h>using namespace std;const int mod = 1e9;const int maxx = 1e5;int in[maxx];vector<int> v[maxx];int main(){ int n, m, x, y; while(~scanf("%d%d",&n,&m)) { //清空图 memset(in, 0, sizeof in); for(int i = 1; i <= n; i ++) { v[i].clear(); } //存图,找度数 while(m --) { scanf("%d%d",&x, &y); v[x].push_back(y); in[y] ++; } priority_queue<int, vector<int>, greater<int> > q; //找到0入度,加入队列 for(int i = 1; i <= n; i ++) { if(in[i] == 0) q.push(i); } int flag = 1; while(!q.empty()) { int xx = q.top(); q.pop(); if(flag) { cout << xx; flag = 0; } else cout << " " << xx; for(int i = 0; i < v[xx].size(); i ++) { in[v[xx][i]] --; if(in[v[xx][i]] == 0) { q.push(v[xx][i]); } } } puts(""); } return 0;}产生冠军Description:有一群人,打乒乓球比赛,两两捉对撕杀,每两个人之间最多打一场比赛。球赛的规则如下:如果A打败了B,B又打败了C,而A与C之间没有进行过比赛,那么就认定,A一定能打败C。如果A打败了B,B又打败了C,而且,C又打败了A,那么A、B、C三者都不可能成为冠军。根据这个规则,无需循环较量,或许就能确定冠军。你的任务就是面对一群比赛选手,在经过了若干场撕杀之后,确定是否已经实际上产生了冠军。Input输入含有一些选手群,每群选手都以一个整数n(n<1000)开头,后跟n对选手的比赛结果,比赛结果以一对选手名字(中间隔一空格)表示,前者战胜后者。如果n为0,则表示输入结束。Output对于每个选手群,若你判断出产生了冠军,则在一行中输出“Yes”,否则在一行中输出“No”。123456789101112131415Sample Input3Alice BobSmith JohnAlice Smith5a cc dd eb ea d0Sample OutputYesNocode:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116//第一种方法//set方法#include<iostream>#include<set>using namespace std;int main(){ int n; string s1, s2; set<string> all, loser; while(~scanf("%d",&n)) { if(n == 0) break; all.clear(); loser.clear(); while(n --) { cin >> s1 >> s2; all.insert(s1); all.insert(s2); loser.insert(s2); } cout << (all.size() - loser.size() == 1 ? "Yes" : "No") << endl; } return 0;}//第二种:#include<iostream>#include<stdio.h>#include<cstring>#include<algorithm>#include<map>using namespace std;const int mod = 1e9;const int maxx = 1e4 + 10;int in[maxx];//int edge[maxx][maxx];//用于构图但是这一题没有用到bool slove(int n){ int sum = 0; for(int i = 1; i <= n; i ++) { if(in[i] == 0) sum ++; } if(sum == 1) return true; return false; }int main(){ int n; map<string, int> mp; while(~scanf("%d",&n)) { if(n == 0) break; //清空图 mp.clear(); memset(in, 0, sizeof in);// memset(edge, 0, sizeof edge);//没用到 string s1, s2; int t = 1; //存图 for(int i = 1; i <= n; i ++) { cin >> s1 >> s2; if(!mp[s1]) mp[s1] = t ++; if(!mp[s2]) mp[s2] = t ++;// edge[mp[s1]][mp[s2]] = 1;//没用到 in[mp[s2]] ++; } t --; if(slove(t)) puts("Yes"); else puts("No"); } return 0;}//第三种://map的另一种做法#include<iostream>#include<cstring>#include<map>using namespace std;int main(){ int n, cnt; map<string, int> mp; string winner, loser; while(~scanf("%d",&n)) { if(n == 0) break; mp.clear(); cnt = 0; for(int i = 1; i <= n; i ++) { cin >> winner >> loser; if(mp.find(winner) == mp.end()) mp[winner] = 1; mp[loser] = 0; } map<string, int> :: iterator it; for(it = mp.begin(); it != mp.end(); it ++) { if(it -> second) cnt ++; } if(cnt == 1) puts("Yes"); else puts("No"); } return 0;}Legal or NotDescription:ACM-DIY is a large QQ group where many excellent acmers get together. It is so harmonious that just like a big family. Every day,many “holy cows” like HH, hh, AC, ZT, lcc, BF, Qinz and so on chat on-line to exchange their ideas. When someone has questions, many warm-hearted cows like Lost will come to help. Then the one being helped will call Lost “master”, and Lost will have a nice “prentice”. By and by, there are many pairs of “master and prentice”. But then problem occurs: there are too many masters and too many prentices, how can we know whether it is legal or not?We all know a master can have many prentices and a prentice may have a lot of masters too, it’s legal. Nevertheless,some cows are not so honest, they hold illegal relationship. Take HH and 3xian for instant, HH is 3xian’s master and, at the same time, 3xian is HH’s master,which is quite illegal! To avoid this,please help us to judge whether their relationship is legal or not.Please note that the “master and prentice” relation is transitive. It means that if A is B’s master ans B is C’s master, then A is C’s master.InputThe input consists of several test cases. For each case, the first line contains two integers, N (members to be tested) and M (relationships to be tested)(2 <= N, M <= 100). Then M lines follow, each contains a pair of (x, y) which means x is y’s master and y is x’s prentice. The input is terminated by N = 0.TO MAKE IT SIMPLE, we give every one a number (0, 1, 2,…, N-1). We use their numbers instead of their names.OutputFor each test case, print in one line the judgement of the messy relationship.If it is legal, output “YES”, otherwise “NO”.1234567891011Sample Input3 20 11 22 20 11 00 0Sample OutputYESNOcode:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051#include<bits/stdc++.h>using namespace std;const int mod = 1e9;const int maxx = 1e5;int in[maxx];vector<int> v[maxx];int main(){ int n, m, x, y; while(~scanf("%d",&n)) { if(n == 0) break; scanf("%d",&m); memset(in, 0, sizeof in); for(int i = 0; i < n; i ++) v[i].clear(); for(int i = 0; i < m; i ++) { cin >> x >> y; v[x].push_back(y); in[y] ++; }// priority_queue<int, vector<int>, greater<int> > q; queue<int> q; int flag = 1, cnt = 0; for(int i = 0; i < n; i ++) { if(in[i] == 0) { q.push(i); } } while(!q.empty()) { int xx = q.front(); q.pop(); n --; if(cnt >= n) continue; for(int i = 0; i < v[xx].size(); i ++) { in[v[xx][i]] --; if(in[v[xx][i]] == 0) q.push(v[xx][i]); } } if(n) puts("NO"); else puts("YES"); } return 0;}RewardDescription:Dandelion’s uncle is a boss of a factory. As the spring festival is coming , he wants to distribute rewards to his workers. Now he has a trouble about how to distribute the rewards.The workers will compare their rewards ,and some one may have demands of the distributing of rewards ,just like a’s reward should more than b’s.Dandelion’s unclue wants to fulfill all the demands, of course ,he wants to use the least money.Every work’s reward will be at least 888 , because it’s a lucky number.InputOne line with two integers n and m ,stands for the number of works and the number of demands .(n<=10000,m<=20000)then m lines ,each line contains two integers a and b ,stands for a’s reward should be more than b’s.OutputFor every case ,print the least money dandelion ‘s uncle needs to distribute .If it’s impossible to fulfill all the works’ demands ,print -1.123456789Sample Input2 11 22 21 22 1Sample Output1777-1code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455#include<bits/stdc++.h>using namespace std;typedef long long ll;const int mod = 1e9;const int maxx = 1e5;int in[maxx], sum[maxx];vector<int> v[maxx];int main(){ int n, m, x, y; while(~scanf("%d %d",&n, &m)) { memset(in, 0, sizeof in); for(int i = 1; i <= n; i ++) v[i].clear(); for(int i = 1; i <= m; i ++) { cin >> y >> x; v[x].push_back(y); in[y] ++; } queue<int> q; int ans = 0, k = 0; for(int i = 1; i <= n; i ++) if(in[i] == 0) { q.push(i); sum[i] = 888; } while(!q.empty()) { int xx = q.front(); q.pop(); k ++; for(int i = 0; i < v[xx].size(); i ++) { in[v[xx][i]] --; if(in[v[xx][i]] == 0) { q.push(v[xx][i]); sum[v[xx][i]] = sum[xx] + 1; } } } for(int i = 1; i <= n; i ++) ans += sum[i]; if(n != k) puts("-1"); else cout << ans << endl; } return 0;}Ordering TasksDescription:John has n tasks to do. Unfortunately, the tasks are not independent and the execution of one task isonly possible if other tasks have already been executed.InputThe input will consist of several instances of the problem. Each instance begins with a line containingtwo integers, 1 ≤ n ≤ 100 and m. n is the number of tasks (numbered from 1 to n) and m is thenumber of direct precedence relations between tasks. After this, there will be m lines with two integersi and j, representing the fact that task i must be executed before task j.An instance with n = m = 0 will finish the input.OutputFor each instance, print a line with n integers representing the tasks in a possible order of execution.123456789Sample Input5 41 22 31 31 50 0Sample Output1 4 2 5 3code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354#include<bits/stdc++.h>using namespace std;const int mod = 1e9;const int maxx = 1e5;int in[maxx];vector<int> v[maxx];int main(){ int n, m, x, y; while(~scanf("%d%d",&n, &m)) { if(n == 0 && m == 0) break; memset(in, 0, sizeof in); for(int i = 1; i <= n; i ++) v[i].clear(); for(int i = 1; i <= m; i ++) { cin >> x >> y; v[x].push_back(y); in[y] ++; }// priority_queue<int, vector<int>, greater<int> > q; queue<int> q; for(int i = 1; i <= n; i ++) { if(in[i] == 0) q.push(i); } int flag = 1; while(!q.empty()) { int xx = q.front(); q.pop(); if(flag) { cout << xx; flag = 0; } else { cout << " " << xx; } for(int i = 0; i < v[xx].size(); i ++) { in[v[xx][i]] --; if(in[v[xx][i]] == 0) q.push(v[xx][i]); } } puts(""); } return 0;}Rank of TetrisDescription:自从Lele开发了Rating系统,他的Tetris事业更是如虎添翼,不久他遍把这个游戏推向了全球。为了更好的符合那些爱好者的喜好,Lele又想了一个新点子:他将制作一个全球Tetris高手排行榜,定时更新,名堂要比福布斯富豪榜还响。关于如何排名,这个不用说都知道是根据Rating从高到低来排,如果两个人具有相同的Rating,那就按这几个人的RP从高到低来排。终于,Lele要开始行动了,对N个人进行排名。为了方便起见,每个人都已经被编号,分别从0到N-1,并且编号越大,RP就越高。同时Lele从狗仔队里取得一些(M个)关于Rating的信息。这些信息可能有三种情况,分别是”A > B”,”A = B”,”A < B”,分别表示A的Rating高于B,等于B,小于B。现在Lele并不是让你来帮他制作这个高手榜,他只是想知道,根据这些信息是否能够确定出这个高手榜,是的话就输出”OK”。否则就请你判断出错的原因,到底是因为信息不完全(输出”UNCERTAIN”),还是因为这些信息中包含冲突(输出”CONFLICT”)。注意,如果信息中同时包含冲突且信息不完全,就输出”CONFLICT”。Input本题目包含多组测试,请处理到文件结束。每组测试第一行包含两个整数N,M(0<=N<=10000,0<=M<=20000),分别表示要排名的人数以及得到的关系数。接下来有M行,分别表示这些关系Output对于每组测试,在一行里按题目要求输出123456789101112131415161718Sample Input3 30 > 11 < 20 > 24 41 = 21 > 32 > 00 > 13 31 > 01 > 22 < 1Sample OutputOKCONFLICTUNCERTAINcode:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697#include <stdio.h>#include <string.h>#include <vector>#include <queue>using namespace std;struct node//边{ int a,b;//顶点 char ch;//运算符}c[10005];vector<int>map[10005];//map数组存贮邻接表int n,m,sum,in[10005],fa[10005];//in数组表示入度,fa[i]表示顶点i所在集合的根节点int find(int x)//查找根节点{ if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x];}bool comb(int x,int y)//合并集合{ x=find(x); y=find(y); if(x==y) return false; else { fa[y]=x; return true; }}void init()//初始化{ for(int i=0;i<n;i++) fa[i]=i;}void top_sort()//queue实现拓扑排序{ queue<int>s; int flag=0; for(int i=0;i<n;i++) { if(in[i]==0&&fa[i]==i) s.push(i); } while(!s.empty()) { if(s.size()>1)//即使发现信息不完整也要继续运行下去,因为如果信息同时不完整和冲突都是CONFLICT flag=1; int pos=s.front(); s.pop(),sum--; for(int i=0;i<map[pos].size();i++) { in[map[pos][i]]--; if(in[map[pos][i]]==0) s.push(map[pos][i]); } } if(sum>0) printf("CONFLICT\n"); else if(flag) printf("UNCERTAIN\n"); else printf("OK\n");}int main(){ while(scanf("%d %d",&n,&m)!=EOF) { sum=n; init(); memset(map,0,sizeof(map)); memset(in,0,sizeof(in)); for(int i=0;i<m;i++) { scanf("%d %c %d",&c[i].a,&c[i].ch,&c[i].b); if(c[i].ch=='=') { if(comb(c[i].a,c[i].b)) sum--; } } for(int i=0;i<m;i++) { if(c[i].ch=='=') continue; int x=find(c[i].a); int y=find(c[i].b); if(c[i].ch=='>') { map[x].push_back(y); in[y]++; } else { map[y].push_back(x); in[x]++; } } top_sort(); }}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
<tag>图论</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day18]]></title>
<url>%2F2019%2F08%2F06%2FDay18%2F</url>
<content type="text"><![CDATA[Day18今天讲的是最短路算法补题OJ链接提醒自己一下,因为今天有事没有写完这些题目,所以大部分的题解和代码都是在网上找到的,希望以后自己可以把这部分题补上最短路算法详情链接->传送最短路Description:在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?Input输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。输入保证至少存在1条商店到赛场的路线。Output对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间1234567891011Sample Input2 11 2 33 31 2 52 3 53 1 20 0Sample Output32code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162#include<iostream>#include<cstring>using namespace std;const int mod = 1e9;const int maxx = 1e3;const int INF = 0x3f3f3f3f;int dis[maxx];bool vis[maxx];int map[maxx][maxx];int dj(int x, int n){ int p; for(int i = 1; i <= n; i ++) dis[i] = map[1][i]; memset(vis, 0, sizeof vis); vis[x] = 1; for(int i = 1; i <= n ; i ++) { int minn = INF; for(int j = 1; j <= n; j ++) { if(!vis[j] && dis[j] < minn) { minn = dis[j]; p = j; } } vis[p] = 1; for(int j = 1; j <= n; j ++) { if(!vis[j] && dis[p] + map[p][j] < dis[j]) dis[j] = dis[p] + map[p][j]; } }}int main(){ int n, m; int a, b, c; while(~scanf("%d%d",&n,&m)) { if(n == 0 && m == 0) break; for(int i = 1; i <= n; i ++) { for(int j = 1; j <= n; j ++) { map[i][j] = INF; } } memset(vis, 0, sizeof vis); for(int i = 1; i <= m; i ++) { cin >> a >> b >> c; if(map[a][b] > c) map[a][b] = map[b][a] = c; } dj(1, n); cout << dis[n] << endl; } return 0;}FroggerDescription:Freddy Frog is sitting on a stone in the middle of a lake. Suddenly he notices Fiona Frog who is sitting on another stone. He plans to visit her, but since the water is dirty and full of tourists’ sunscreen, he wants to avoid swimming and instead reach her by jumping.Unfortunately Fiona’s stone is out of his jump range. Therefore Freddy considers to use other stones as intermediate stops and reach her by a sequence of several small jumps.To execute a given sequence of jumps, a frog’s jump range obviously must be at least as long as the longest jump occuring in the sequence.The frog distance (humans also call it minimax distance) between two stones therefore is defined as the minimum necessary jump range over all possible paths between the two stones.You are given the coordinates of Freddy’s stone, Fiona’s stone and all other stones in the lake. Your job is to compute the frog distance between Freddy’s and Fiona’s stone.InputThe input will contain one or more test cases. The first line of each test case will contain the number of stones n (2<=n<=200). The next n lines each contain two integers xi,yi (0 <= xi,yi <= 1000) representing the coordinates of stone #i. Stone #1 is Freddy’s stone, stone #2 is Fiona’s stone, the other n-2 stones are unoccupied. There’s a blank line following each test case. Input is terminated by a value of zero (0) for n.OutputFor each test case, print a line saying “Scenario #x” and a line saying “Frog Distance = y” where x is replaced by the test case number (they are numbered from 1) and y is replaced by the appropriate real number, printed to three decimals. Put a blank line after each test case, even after the last one.1234567891011121314151617Sample Input20 03 4317 419 418 50Sample OutputScenario #1Frog Distance = 5.000Scenario #2Frog Distance = 1.414code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154//Floyd解法#include <cstdio>#include <cstring>#include <string>#include <iostream>#include <stack>#include <queue>#include <vector>#include <cmath>#include <algorithm>#define mem(a,b) memset(a,b,sizeof(a))#define maxnum 300#define inf 0x3f3f3f3fusing namespace std;int x[maxnum],y[maxnum],n;double map[maxnum][maxnum];void floyd(){ for(int k=1; k<=n; k++) for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) map[i][j]=min(map[i][j],max(map[i][k],map[k][j]));//许多通路中最长边中的最小边}int main(){ int q=1; while(~scanf("%d",&n)&&n) { mem(map,0); for(int i=1; i<=n; i++) scanf("%d%d",&x[i],&y[i]); for(int i=1; i<=n; i++) for(int j=i+1; j<=n; j++) map[i][j]=map[j][i]=sqrt(double(x[i]-x[j])*(x[i]-x[j])+double(y[i]-y[j])*(y[i]-y[j])); floyd(); printf("Scenario #%d\nFrog Distance = %.3lf\n\n",q++,map[1][2]); } return 0;}//dijkstra解法#include <cstdio>#include <cstring>#include <string>#include <iostream>#include <stack>#include <queue>#include <vector>#include <cmath>#include <algorithm>#define mem(a,b) memset(a,b,sizeof(a))#define maxnum 300#define inf 0x3f3f3f3fusing namespace std;int x[maxnum],y[maxnum],n;double map[maxnum][maxnum];double dis[maxnum];int vis[maxnum];void dj(int s){ mem(vis,0); for(int i=1; i<=n; i++) dis[i]=inf;//这里最好别用memset dis[s]=0; for(int i=1; i<=n; i++) { int minn=inf,k; for(int j=1; j<=n; j++) if(vis[j]==0&&dis[j]<minn) { k=j; minn=dis[j]; } vis[k]=1; for(int j=1; j<=n; j++) dis[j]=min(dis[j],max(dis[k],map[k][j]));//dis[j]为从一号石头到第j号石头所有通路中最长边中的最小边 }}int main(){ int q=1; while(~scanf("%d",&n)&&n) { mem(map,0); for(int i=1; i<=n; i++) scanf("%d%d",&x[i],&y[i]); for(int i=1; i<=n; i++) for(int j=i+1; j<=n; j++) map[i][j]=map[j][i]=sqrt(double(x[i]-x[j])*(x[i]-x[j])+double(y[i]-y[j])*(y[i]-y[j])); dj(1); printf("Scenario #%d\nFrog Distance = %.3lf\n\n",q++,dis[2]); } return 0;}//SPFA解法#include <cstdio>#include <cstring>#include <string>#include <iostream>#include <stack>#include <queue>#include <vector>#include <cmath>#include <algorithm>#define mem(a,b) memset(a,b,sizeof(a))#define maxnum 300#define inf 0x3f3f3f3fusing namespace std;int x[maxnum],y[maxnum],n;double map[maxnum][maxnum];double dis[maxnum];int vis[maxnum];void spfa(){ queue<int>q; for(int i=1; i<=n; i++) dis[i]=inf; dis[1]=0; for(int i=1; i<=n; i++) vis[i]=0; vis[1]=1; q.push(1); while(!q.empty()) { int k=q.front(); vis[k]=0; q.pop(); for(int j=1; j<=n; j++) if(max(dis[k],map[k][j])<dis[j]) { dis[j]=max(dis[k],map[k][j]); if(vis[j]==0) { q.push(j); vis[j]=1; } } }}int main(){ int q=1; while(~scanf("%d",&n)&&n) { mem(map,0); for(int i=1; i<=n; i++) scanf("%d%d",&x[i],&y[i]); for(int i=1; i<=n; i++) for(int j=i+1; j<=n; j++) map[i][j]=map[j][i]=sqrt(double(x[i]-x[j])*(x[i]-x[j])+double(y[i]-y[j])*(y[i]-y[j])); spfa(); printf("Scenario #%d\nFrog Distance = %.3lf\n\n",q++,dis[2]); } return 0;}Stockbroker GrapevineDescription:Stockbrokers are known to overreact to rumours. You have been contracted to develop a method of spreading disinformation amongst the stockbrokers to give your employer the tactical edge in the stock market. For maximum effect, you have to spread the rumours in the fastest possible way.Unfortunately for you, stockbrokers only trust information coming from their “Trusted sources” This means you have to take into account the structure of their contacts when starting a rumour. It takes a certain amount of time for a specific stockbroker to pass the rumour on to each of his colleagues. Your task will be to write a program that tells you which stockbroker to choose as your starting point for the rumour, as well as the time it will take for the rumour to spread throughout the stockbroker community. This duration is measured as the time needed for the last person to receive the information.InputYour program will input data for different sets of stockbrokers. Each set starts with a line with the number of stockbrokers. Following this is a line for each stockbroker which contains the number of people who they have contact with, who these people are, and the time taken for them to pass the message to each person. The format of each stockbroker line is as follows: The line starts with the number of contacts (n), followed by n pairs of integers, one pair for each contact. Each pair lists first a number referring to the contact (e.g. a ‘1’ means person number one in the set), followed by the time in minutes taken to pass a message to that person. There are no special punctuation symbols or spacing rules.Each person is numbered 1 through to the number of stockbrokers. The time taken to pass the message on will be between 1 and 10 minutes (inclusive), and the number of contacts will range between 0 and one less than the number of stockbrokers. The number of stockbrokers will range from 1 to 100. The input is terminated by a set of stockbrokers containing 0 (zero) people.OutputFor each set of data, your program must output a single line containing the person who results in the fastest message transmission, and how long before the last person will receive any given message after you give it to this person, measured in integer minutes.It is possible that your program will receive a network of connections that excludes some persons, i.e. some people may be unreachable. If your program detects such a broken network, simply output the message “disjoint”. Note that the time taken to pass the message from person A to person B is not necessarily the same as the time taken to pass it from B to A, if such transmission is possible at all.123456789101112131415Sample Input32 2 4 3 52 1 2 3 62 1 2 2 253 4 4 2 8 5 31 5 84 1 6 4 10 2 7 5 202 2 5 1 50Sample Output3 23 10code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162/*经典水题floyd这道题重点在于找到从某一个源点出发的最短路怎么找?可以找到从一个源点出发最长的时间,即是传递结束,然后找最长的最短。当然会出现有些人没有传递到,但是这道题的bug在于此,不会出现disjoint的情况。*/#include<iostream>#include<cstring>using namespace std;#define inf 20#define M 210int dist[M][M];int n;void floyd(){ for(int k = 1;k <= n; k++) for(int i = 1;i <= n; i++) for(int j = 1;j <= n; j++) if(i != j && dist[i][j] > dist[i][k] + dist[k][j]) dist[i][j] = dist[i][k] + dist[k][j]; int minlength = inf; int maxlength,pos; for(int i = 1;i <= n; i++){ maxlength = 0; for(int j = 1;j <= n; j++) if(i != j && maxlength < dist[i][j]) maxlength = dist[i][j]; if(minlength > maxlength){ minlength = maxlength; pos = i; } } cout<<pos<<" "<<minlength<<endl;;}int main(){ while(1){ memset(dist,inf,sizeof(dist)); cin>>n; if(!n) break; for(int i = 1;i <= n; i++){ int n1; cin>>n1; for(int j = 1;j <= n1; j++){ int p,t; cin>>p>>t; dist[i][p] = t; } } floyd(); } return 0;}Invitation CardsDescription:In the age of television, not many people attend theater performances. Antique Comedians of Malidinesia are aware of this fact. They want to propagate theater and, most of all, Antique Comedies. They have printed invitation cards with all the necessary information and with the programme. A lot of students were hired to distribute these invitations among the people. Each student volunteer has assigned exactly one bus stop and he or she stays there the whole day and gives invitation to people travelling by bus. A special course was taken where students learned how to influence people and what is the difference between influencing and robbery.The transport system is very special: all lines are unidirectional and connect exactly two stops. Buses leave the originating stop with passangers each half an hour. After reaching the destination stop they return empty to the originating stop, where they wait until the next full half an hour, e.g. X:00 or X:30, where ‘X’ denotes the hour. The fee for transport between two stops is given by special tables and is payable on the spot. The lines are planned in such a way, that each round trip (i.e. a journey starting and finishing at the same stop) passes through a Central Checkpoint Stop (CCS) where each passenger has to pass a thorough check including body scan.All the ACM student members leave the CCS each morning. Each volunteer is to move to one predetermined stop to invite passengers. There are as many volunteers as stops. At the end of the day, all students travel back to CCS. You are to write a computer program that helps ACM to minimize the amount of money to pay every day for the transport of their employees.InputThe input consists of N cases. The first line of the input contains only positive integer N. Then follow the cases. Each case begins with a line containing exactly two integers P and Q, 1 <= P,Q <= 1000000. P is the number of stops including CCS and Q the number of bus lines. Then there are Q lines, each describing one bus line. Each of the lines contains exactly three numbers - the originating stop, the destination stop and the price. The CCS is designated by number 1. Prices are positive integers the sum of which is smaller than 1000000000. You can also assume it is always possible to get from any stop to any other stop.OutputFor each case, print one line containing the minimum amount of money to be paid each day by ACM for the travel costs of its volunteers.123456789101112131415Sample Input22 21 2 132 1 334 61 2 102 1 601 3 203 4 102 4 54 1 50Sample Output46210题意求1到各个顶点和各个定点到1的路线总长最短。有向图。code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283//各个点到1顶点的总和最短可以反向建图来实现。而不是反复最短路//因为有1000000的顶点所以采用了邻接表。#include <iostream>#include <string.h>#include <stdio.h>#include <queue>using namespace std;const int N = 1000000+100;const int inf=0x3f3f3f3f;int b[N],w[N],e[N];int fir[N],nxt[N];int n,m;int dis[N];int vis[N];void spfa(int &ans){ memset(vis,0,sizeof vis); for(int i=1;i<=n;i++) { dis[i]=i==1?0:inf; } dis[1]=0;vis[1]=1; queue<int> q; while(!q.empty()) q.pop(); q.push(1); while(!q.empty()) { int now=q.front(); int k=fir[now]; q.pop(); vis[now]=0; while(k!=-1) { if(dis[e[k]]>dis[b[k]]+w[k]) { dis[e[k]]=dis[b[k]]+w[k]; if(!vis[e[k]]) q.push(e[k]),vis[e[k]]=1; } k=nxt[k]; } } for(int i=1;i<=n;i++) { ans+=dis[i]; }}int main(){ int t; scanf("%d",&t); while(t--) { int ans=0; scanf("%d %d",&n,&m); for(int i=1; i<=n; i++) { fir[i]=-1; nxt[i]=-1; dis[i]=inf; } for(int i=1; i<=m; i++) { scanf("%d %d %d",&b[i],&e[i],&w[i]); nxt[i]=fir[b[i]]; fir[b[i]]=i; } spfa(ans); memset(nxt,-1,sizeof nxt); memset(fir,-1,sizeof fir); for(int i=1; i<=m; i++) { int t=b[i]; b[i]=e[i]; e[i]=t; nxt[i]=fir[b[i]]; fir[b[i]]=i; } spfa(ans); printf("%d\n",ans); }}SkiingDescription:Bessie and the rest of Farmer John’s cows are taking a trip this winter to go skiing. One day Bessie finds herself at the top left corner of an R (1 <= R <= 100) by C (1 <= C <= 100) grid of elevations E (-25 <= E <= 25). In order to join FJ and the other cows at a discow party, she must get down to the bottom right corner as quickly as she can by travelling only north, south, east, and west.Bessie starts out travelling at a initial speed V (1 <= V <= 1,000,000). She has discovered a remarkable relationship between her speed and her elevation change. When Bessie moves from a location of height A to an adjacent location of eight B, her speed is multiplied by the number 2^(A-B). The time it takes Bessie to travel from a location to an adjacent location is the reciprocal of her speed when she is at the first location.Find the both smallest amount of time it will take Bessie to join her cow friends.InputLine 1: Three space-separated integers: V, R, and C, which respectively represent Bessie’s initial velocity and the number of rows and columns in the grid.Lines 2..R+1: C integers representing the elevation E of the corresponding location on the grid.OutputA single number value, printed to two exactly decimal places: the minimum amount of time that Bessie can take to reach the bottom right corner of the grid.1234567891011121314Sample Input1 3 31 5 36 3 52 4 3Sample Output29.00HintBessie's best route is:Start at 1,1 time 0 speed 1East to 1,2 time 1 speed 1/16South to 2,2 time 17 speed 1/4South to 3,2 time 21 speed 1/8East to 3,3 time 29 speed 1/4code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162//dijkstra解法/*dijkstra解法题解:每个节点的耗时就是从左上角(1,1)点到(i,j)点的2^高度差,而速度是其倒数,需输出的啦~,先把节点存储成耗时的静态邻接表,然后利用dijkstra的堆优化进行(nlogn)的求解。*/#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#include<queue>#include<cmath>#define eps 1e-8#define maxn 111#define inf 999999999999using namespace std;struct node{ int x; int y; double dis; bool operator < (const node &a) const{ return dis>a.dis; }};int dic[4][2]={0,1,1,0,-1,0,0,-1};int at[maxn][maxn];double mp[maxn][maxn];double dis[maxn][maxn];bool vis[maxn][maxn];int v,r,c;void init(){ for(int i=1;i<=r;i++) for(int j=1;j<=c;j++) dis[i][j]=inf; memset(vis,0,sizeof(vis));}double get_cost(int h){ return v*1.0*pow(2*1.0,at[1][1]-h);}bool ok(int x,int y){ if(x>0&&x<=r&&y>0&&y<=c) return true; else return false;}void dijkstra(){ priority_queue<node> q; node now,next; now.x=1; now.y=1; now.dis=0; dis[1][1]=0; q.push(now); while(!q.empty()) { now=q.top(); q.pop(); if(vis[now.x][now.y]) continue; vis[now.x][now.y]=true; if(now.x==r&&now.y==c) break; int x;int y; for(int i=0;i<4;i++) { x=now.x+dic[i][0]; y=now.y+dic[i][1]; if(!ok(x,y)) continue; if(!vis[x][y]&&dis[x][y]>now.dis+1.0/mp[now.x][now.y]) { dis[x][y]=now.dis+1.0/mp[now.x][now.y]; next.x=x; next.y=y; next.dis=dis[x][y]; q.push(next); } } }}int main(){ scanf("%d%d%d",&v,&r,&c); init(); //printf("%lf\n",dis[1][1]); for(int i=1;i<=r;i++) for(int j=1;j<=c;j++) scanf("%d",&at[i][j]); for(int i=1;i<=r;i++) for(int j=1;j<=c;j++) mp[i][j]=get_cost(at[i][j]); dijkstra(); printf("%.2f\n",dis[r][c]); return 0;}//SPFA解法/*题解:可以看出每个点的速度都与第一个点有关,因为V*2^(A-B)*2^(B-C)它就等于V*2^(A-C),所以每个点的速度都可以用第一个点算出来。然后把每个点对应到下一个点的时间存到这个点的位置上。*/#include <iostream>#include <cstring>#include <queue>#include <cmath>#include <cfloat>#include <cstdio>using namespace std;const double inf = 0x3f3f3f3f;const int MAX = 200;int v,r,c;int vis[MAX][MAX];double mp[MAX][MAX],t[MAX][MAX],dis[MAX][MAX];// mp要用double 待会用到pow函数要不然报错int mv[4][2]={{0,1},{0,-1},{1,0},{-1,0}};struct hh{ int x,y;};void spfa(){ memset(vis,0,sizeof(vis)); for(int i=1;i<=r;i++){// 赋一个很大的值给double类型的数组,要用这种形式,要不然用下面那种形式,不对。 for(int j=1;j<=c;j++){ dis[i][j] = DBL_MAX; } } //memset(dis,inf,sizeof(dis)); queue<hh> q; hh tmp,nex; int xx,yy; tmp.x=1; tmp.y=1; dis[1][1]=0;//注意赋值为0,dis数组表示别的点到这个点需要的时间,不包括这个点到别的点的时间,也就是不包括这个点所存的时间 q.push(tmp); while(!q.empty()){ tmp=q.front(); q.pop(); vis[tmp.x][tmp.y]=0;// 注意要赋值0,要不然会错,因为这个点我们可能需要重新走 for (int i = 0; i < 4;i++){ xx=tmp.x+mv[i][0]; yy=tmp.y+mv[i][1]; if(xx<1|yy<1||xx>r||yy>c) continue; if(dis[xx][yy]>t[tmp.x][tmp.y]+dis[tmp.x][tmp.y]){ dis[xx][yy]=t[tmp.x][tmp.y]+dis[tmp.x][tmp.y]; if(!vis[xx][yy]){ vis[xx][yy]=1; nex.x=xx; nex.y=yy; q.push(nex); } } } }}int main(){ cin >> v >> r >> c; for (int i = 1; i <= r;i++){ for (int j = 1; j <= c;j++){ cin >> mp[i][j]; t[i][j]=1/(v*(pow(2,mp[1][1]-mp[i][j])));//计算每个点到下一个点所需要的时间,存到这个点上 } } spfa(); printf("%.2lf\n",dis[r][c]); return 0;}Cow HurdlesDescription:Farmer John wants the cows to prepare for the county jumping competition, so Bessie and the gang are practicing jumping over hurdles. They are getting tired, though, so they want to be able to use as little energy as possible to jump over the hurdles.Obviously, it is not very difficult for a cow to jump over several very short hurdles, but one tall hurdle can be very stressful. Thus, the cows are only concerned about the height of the tallest hurdle they have to jump over.The cows’ practice room has N (1 ≤ N ≤ 300) stations, conveniently labeled 1..N. A set of M (1 ≤ M ≤ 25,000) one-way paths connects pairs of stations; the paths are also conveniently labeled 1..M. Path i travels from station Si to station Ei and contains exactly one hurdle of height Hi (1 ≤ Hi ≤ 1,000,000). Cows must jump hurdles in any path they traverse.The cows have T (1 ≤ T ≤ 40,000) tasks to complete. Task i comprises two distinct numbers, Ai and Bi (1 ≤ Ai ≤ N; 1 ≤ Bi ≤ N), which connote that a cow has to travel from station Ai to station Bi (by traversing over one or more paths over some route). The cows want to take a path the minimizes the height of the tallest hurdle they jump over when traveling from Ai to Bi . Your job is to write a program that determines the path whose tallest hurdle is smallest and report that height.InputLine 1: Three space-separated integers: N, M, and TLines 2..M+1: Line i+1 contains three space-separated integers: Si , Ei , and HiLines M+2..M+T+1: Line i+M+1 contains two space-separated integers that describe task i: Ai and BiOutputLines 1..T: Line i contains the result for task i and tells the smallest possible maximum height necessary to travel between the stations. Output -1 if it is impossible to travel between the two stations.123456789101112131415ample Input5 6 31 2 123 2 81 3 52 5 33 4 42 4 83 41 25 1Sample Output48-1题意:有一头牛,要进行跳木桩训练,已知有n个木桩,而且知道m对木桩之间的高度差。但是它很懒,它想尽可能的跳最小的高度就完成从任意一个木桩到任意一个木桩的跳跃,给m对点,问是否存在最小的跳跃高度使得其能够完成跳跃,如果有就输出最小高度;否则输出-1。解析:对于每一次询问,求的是每条路径上边权值的最大值(该路径所经过的相邻两木桩之间的差值的最大值),然后取其中的最小值即可。因为只要能跳过这个高度差最大的,高度差小的当然能跳过去了。由于是求任意两木桩之间的所有路径上最大高度差值的最小值,所以我们可以用Floyd算法,对其进行处理,处理之后得到的最终结果即为所求了。code:1234567891011121314151617181920212223242526272829#include <cstdio>#include <iostream>#include <algorithm>using namespace std;#define INF 123456789int a[302][302]; //最大高度的最小值矩阵int main(){ int n, m, t; int x, y, w; while(scanf("%d%d%d", &n, &m, &t)!=EOF){ for(int i=1; i<=n; i++) //初始化 for(int j=1; j<=n; j++) a[i][j] = i==j ? 0 : INF; for(int i=1; i<=m; i++){ //读入高度差 scanf("%d%d%d", &x, &y, &w); a[x][y] = min(a[x][y], w); //更新最大高度差 } for(int k=1; k<=n; k++) //Floyd for(int i=1; i<=n; i++) for(int j=1; j<=n; j++){ a[i][j] = min(a[i][j], max(a[i][k], a[k][j])); } for(int i=1; i<=t; i++){ scanf("%d%d", &x, &y); printf("%d\n", a[x][y]==INF ? -1 : a[x][y]); //输出,如果还是INF,那就代表不可达,两者时之间没有路径满足要求 } } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
<tag>图论</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day17]]></title>
<url>%2F2019%2F08%2F05%2FDay17%2F</url>
<content type="text"><![CDATA[Day17今天讲的是并查集和最小生成树OJ链接并查集+最小生成树具体内容点这里->链接The SuspectsDescription:Severe acute respiratory syndrome (SARS), an atypical pneumonia of unknown aetiology, was recognized as a global threat in mid-March 2003. To minimize transmission to others, the best strategy is to separate the suspects from others.In the Not-Spreading-Your-Sickness University (NSYSU), there are many student groups. Students in the same group intercommunicate with each other frequently, and a student may join several groups. To prevent the possible transmissions of SARS, the NSYSU collects the member lists of all student groups, and makes the following rule in their standard operation procedure (SOP).Once a member in a group is a suspect, all members in the group are suspects.However, they find that it is not easy to identify all the suspects when a student is recognized as a suspect. Your job is to write a program which finds all the suspects.InputThe input file contains several cases. Each test case begins with two integers n and m in a line, where n is the number of students, and m is the number of groups. You may assume that 0 < n <= 30000 and 0 <= m <= 500. Every student is numbered by a unique integer between 0 and n−1, and initially student 0 is recognized as a suspect in all the cases. This line is followed by m member lists of the groups, one line per group. Each line begins with an integer k by itself representing the number of members in the group. Following the number of members, there are k integers representing the students in this group. All the integers in a line are separated by at least one space.A case with n = 0 and m = 0 indicates the end of the input, and need not be processed.OutputFor each case, output the number of suspects in one line.123456789101112131415Sample Input100 42 1 25 10 13 11 12 142 0 12 99 2200 21 55 1 2 3 4 51 00 0Sample Output411code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859#include<stdio.h>#include<algorithm>#include<iostream>#include<queue>using namespace std;const int mod = 1e9;const int maxx = 1e5;int pre[maxx];int sum;int find(int x){ int r = x; while(pre[r] != r) { r = pre[r]; } //路径压缩算法 int i = x, j; while(pre[i] != r) { j = pre[r]; pre[i] = r; i = j; } return r;}void join(int x, int y){ int xx = find(x), yy = find(y); if(xx != yy) pre[xx] = yy;}int main(){ int n, m, k; while(~scanf("%d %d",&n, &m)) { sum = 0; if(n == 0 && m == 0) break; for(int i = 0; i < n; i ++) pre[i] = i; for(int i = 1; i <= m; i ++) { scanf("%d",&k); int num1, num; scanf("%d",&num1); k --; while(k --) { scanf("%d", &num); join(num1, num); num1 = num; } } for(int i = 0; i < n; i ++) if(find(i) == pre[0]) sum ++; printf("%d\n", sum); } return 0;}畅通工程Description:某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?Input测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。注意:两个城市之间可以有多条道路相通,也就是说3 31 21 22 1这种输入也是合法的当N为0时,输入结束,该用例不被处理。Output对每个测试用例,在1行里输出最少还需要建设的道路数目。1234567891011121314151617181920Sample Input4 21 34 33 31 21 32 35 21 23 5999 00Sample Output102998Huge input, scanf is recommended.code:123456789101112131415161718192021222324252627282930313233343536373839404142434445#include<stdio.h>#include<algorithm>#include<iostream>#include<queue>using namespace std;const int mod = 1e9;const int maxx = 1e5;int pre[maxx];int find(int x){ int r = x; while(pre[r] != r) { r = pre[r]; } return r;}void join(int x, int y){ int xx = find(x), yy = find(y); if(xx != yy) pre[xx] = yy;}int main(){ int n, m; int x, y; while(scanf("%d",&n)!=EOF) { if(n == 0) break; scanf("%d",&m); for(int i = 1; i <= n; i ++) pre[i] = i; for(int i = 0; i < m; i ++) { scanf("%d %d",&x, &y); join(x, y); } int ans = 0; for(int i = 1; i <= n; i ++) if(pre[i] == i) ans ++; cout << ans - 1 << endl; } return 0;}还是畅通工程Description:某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。Input测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。当N为0时,输入结束,该用例不被处理。Output对每个测试用例,在1行里输出最小的公路总长度。123456789101112131415161718Sample Input31 2 11 3 22 3 441 2 11 3 41 4 12 3 32 4 23 4 50Sample Output35Huge input, scanf is recommended.code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859#include<stdio.h>#include<algorithm>#include<iostream>#include<queue>using namespace std;const int mod = 1e9;const int maxx = 1e5;int pre[maxx];int t;struct node{ int s, e, w;}e_e[maxx];int cmp(node x, node y){ return x.w < y.w;}int find(int x){ int r = x; while(pre[r] != r) { r = pre[r]; } return r;}int kru(){ int len = t * (t - 1) / 2; int ans = 0; for(int i = 1; i <= len; i ++) pre[i] = i; sort(e_e + 1, e_e + len + 1, cmp); for(int i = 1; i <= len; i ++) { int xx = find(e_e[i].s); int yy = find(e_e[i].e); if(xx != yy) { ans += e_e[i].w; pre[xx] = yy; } } return ans;}int main(){ while(~scanf("%d",&t)) { if(t == 0) break; int len = t * (t - 1) / 2; for(int i = 1; i <= len; i ++) { scanf("%d %d %d",&e_e[i].s, &e_e[i].e, &e_e[i].w); } int ans = kru(); cout << ans << endl; } return 0;}Ubiquitous ReligionsDescription:There are so many different religions in the world today that it is difficult to keep track of them all. You are interested in finding out how many different religions students in your university believe in.You know that there are n students in your university (0 < n <= 50000). It is infeasible for you to ask every student their religious beliefs. Furthermore, many students are not comfortable expressing their beliefs. One way to avoid these problems is to ask m (0 <= m <= n(n-1)/2) pairs of students and ask them whether they believe in the same religion (e.g. they may know if they both attend the same church). From this data, you may not know what each person believes in, but you can get an idea of the upper bound of how many different religions can be possibly represented on campus. You may assume that each student subscribes to at most one religion.InputThe input consists of a number of cases. Each case starts with a line specifying the integers n and m. The next m lines each consists of two integers i and j, specifying that students i and j believe in the same religion. The students are numbered 1 to n. The end of input is specified by a line in which n = m = 0.OutputFor each test case, print on a single line the case number (starting with 1) followed by the maximum number of different religions that the students in the university believe in.12345678910111213141516171819202122Sample Input10 91 21 31 41 51 61 71 81 91 1010 42 34 54 85 80 0Sample OutputCase 1: 1Case 2: 7HintHuge input, scanf is recommended.code:123456789101112131415161718192021222324252627282930313233343536373839404142434445#include<stdio.h>#include<algorithm>#include<iostream>#include<queue>using namespace std;const int mod = 1e9;const int maxx = 1e5;int pre[maxx];int find(int x){ int r = x; while(pre[r] != r) { r = pre[r]; } return r;}void join(int x, int y){ int xx = find(x), yy = find(y); if(xx != yy) pre[xx] = yy;}int main(){ int n, m; int x, y; int k = 1; while(scanf("%d %d",&n,&m)!=EOF) { if(n == 0 && m == 0) break; for(int i = 1; i <= n; i ++) pre[i] = i; for(int i = 0; i < m; i ++) { scanf("%d %d",&x, &y); join(y, x); } int ans = 0; for(int i = 1; i <= n; i ++) if(pre[i] == i) ans ++; printf("Case %d: %d\n",k ++, ans); } return 0;}Cube StackingDescription:Farmer John and Betsy are playing a game with N (1 <= N <= 30,000)identical cubes labeled 1 through N. They start with N stacks, each containing a single cube. Farmer John asks Betsy to perform P (1<= P <= 100,000) operation. There are two types of operations:moves and counts.In a move operation, Farmer John asks Bessie to move the stack containing cube X on top of the stack containing cube Y.In a count operation, Farmer John asks Bessie to count the number of cubes on the stack with cube X that are under the cube X and report that value.Write a program that can verify the results of the game.InputLine 1: A single integer, PLines 2..P+1: Each of these lines describes a legal operation. Line 2 describes the first operation, etc. Each line begins with a ‘M’ for a move operation or a ‘C’ for a count operation. For move operations, the line also contains two integers: X and Y.For count operations, the line also contains a single integer: X.Note that the value for N does not appear in the input file. No move operation will request a move a stack onto itself.OutputPrint the output from each of the count operations in the same order as the input file.123456789101112Sample Input6M 1 6C 1M 2 4M 2 6C 3C 4Sample Output102code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354#include<stdio.h>#include<algorithm>#include<iostream>using namespace std;const int maxx = 1e5;int pre[maxx], dis[maxx], cnt[maxx];int find(int x){ if(pre[x] != x) { int tmp = pre[x]; pre[x] = find(pre[x]); dis[x] += dis[tmp]; } return pre[x];}void join(int x, int y){ pre[x] = y; dis[x] += cnt[y]; cnt[y] += cnt[x];}int main(){ int n; scanf("%d",&n); for(int i = 0; i < 31000; i ++) { pre[i] = i; cnt[i] = 1; dis[i] = 0; } while(n --) { char ch; int a, b; cin >> ch; if(ch == 'M') { scanf("%d %d",&a, &b); if(find(a) != find(b)) join(find(a), find(b)); } else { int x; scanf("%d",&x); find(x); printf("%d\n",dis[x]); } } return 0;}Dragon BallsDescription:Five hundred years later, the number of dragon balls will increase unexpectedly, so it’s too difficult for Monkey King(WuKong) to gather all of the dragon balls together.His country has N cities and there are exactly N dragon balls in the world. At first, for the ith dragon ball, the sacred dragon will puts it in the ith city. Through long years, some cities’ dragon ball(s) would be transported to other cities. To save physical strength WuKong plans to take Flying Nimbus Cloud, a magical flying cloud to gather dragon balls.Every time WuKong will collect the information of one dragon ball, he will ask you the information of that ball. You must tell him which city the ball is located and how many dragon balls are there in that city, you also need to tell him how many times the ball has been transported so far.InputThe first line of the input is a single positive integer T(0 < T <= 100).For each case, the first line contains two integers: N and Q (2 < N <= 10000 , 2 < Q <= 10000).Each of the following Q lines contains either a fact or a question as the follow format:T A B : All the dragon balls which are in the same city with A have been transported to the city the Bth ball in. You can assume that the two cities are different.Q A : WuKong want to know X (the id of the city Ath ball is in), Y (the count of balls in Xth city) and Z (the tranporting times of the Ath ball). (1 <= A, B <= N)OutputFor each test case, output the test case number formated as sample output. Then for each query, output a line with three integers X Y Z saparated by a blank space.题目大意:有标号为1到n的n个龙珠,分别放在对应标号为1到n的n个城市里。下面有两种操作:T A B表示把A龙珠所在城市的所有龙珠都转移到B龙珠所在的城市中Q A 表示查询A,需要知道A龙珠现在所在的城市,A所在的城市有几颗龙珠,A转移到这个城市移动了多少次,分别输出3个整数,表示上述信息。1234567891011121314151617Sample Input23 3T 1 2T 3 2Q 23 4T 1 2Q 1T 1 3Q 1Sample OutputCase 1:2 3 0Case 2:2 2 13 3 2没写出来,先看着别人的代码和详解吧code:详细链接123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172#include <iostream>#include <cstring>#include <cstdio>using namespace std;const int maxn = 10005;int pre[maxn];//pre[i]表示第i个球所在的城市int sum[maxn];//sum[i]表示第i个城市所拥有的球的个数int cnt[maxn];//cnt[i]表示第i个球移动了几次int n,m,root;char str[3];//初始化,每一个球原来都呆在自己的城市,所以每一个城市里都只有1个球,每一个球的移动次数都是0。void init(){ for(int i=0;i<maxn;i++) { pre[i] = i; sum[i] = 1; cnt[i] = 0; }}int find(int x){ if(x==pre[x]) return x; int fx = find(pre[x]); cnt[x] += cnt[pre[x]]; pre[x] = fx; return fx;}void join(int x,int y){ int fx = find(x); int fy = find(y); if(fy==fx) return ; pre[fx] = fy; sum[fy] += sum[fx]; sum[fx] = 0; cnt[fx] = 1;}int main (){ int T,k=1,i; int x,y,a; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); printf("Case %d:\n",k++); init(); while(m--) { scanf("%s",str); if(str[0]=='T') { scanf("%d%d",&x,&y); join(x,y); } else if(str[0]=='Q') { scanf("%d",&a); root = find(a); printf("%d %d %d\n",root,sum[root],cnt[a]); } } } return 0;}Zjnu StadiumDescription:In 12th Zhejiang College Students Games 2007, there was a new stadium built in Zhejiang Normal University. It was a modern stadium which could hold thousands of people. The audience Seats made a circle. The total number of columns were 300 numbered 1–300, counted clockwise, we assume the number of rows were infinite.These days, Busoniya want to hold a large-scale theatrical performance in this stadium. There will be N people go there numbered 1–N. Busoniya has Reserved several seats. To make it funny, he makes M requests for these seats: A B X, which means people numbered B must seat clockwise X distance from people numbered A. For example: A is in column 4th and X is 2, then B must in column 6th (6=4+2).Now your task is to judge weather the request is correct or not. The rule of your judgement is easy: when a new request has conflicts against the foregoing ones then we define it as incorrect, otherwise it is correct. Please find out all the incorrect requests and count them as R.InputThere are many test cases:For every case:The first line has two integer N(1<=N<=50,000), M(0<=M<=100,000),separated by a space.Then M lines follow, each line has 3 integer A(1<=A<=N), B(1<=B<=N), X(0<=X<300) (A!=B), separated by a space.OutputFor every case:Output R, represents the number of incorrect request.1234567891011121314151617Sample Input10 101 2 1503 4 2001 5 2702 6 2006 5 804 7 1508 9 1004 8 501 7 1009 2 100Sample Output2Hint:(PS: the 5th and 10th requests are incorrect)code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556//题目大意:给你n个人,m个关系,关系表示b在距离a顺时针方向的X距离的地、询问有哪些信息需要改正(也就是错的)。/*其中A表示a的祖先,B表示b的祖先,suma表示a到A的权值 ,sumb表示b到B的权值,我们已知a,b间距离,那么x也是可求距离。那么如果两个节点已经连接了,那么如何判断这两个节点之间的距离确实是w呢?直接用sum【b】-sum【a】就能得到a,b之间真实距离,如果和w不等,那么说明这条边需要更改消息。也就是说output要加1了*/#include<iostream>#include<stdio.h>#include<string.h>using namespace std;int f[1000010];int sum[1000010];int find(int x){ if(x!=f[x]) { //pre是x的一个父节点。 int pre=f[x]; //递归找祖先。 f[x]=find(f[x]); sum[x]+=sum[pre]; } return f[x];}int main(){ int n,m; while(~scanf("%d%d",&n,&m)) { int output=0; for(int i=0; i<=n; i++) { f[i]=i; sum[i]=0; } for(int i=0; i<m; i++) { int x,y,w; scanf("%d%d%d",&x,&y,&w); int xx=find(x); int yy=find(y); if(xx==yy) { if(sum[y]-sum[x]!=w) { output++; } } else { sum[yy]=w-sum[y]+sum[x]; f[yy]=xx; } } printf("%d\n",output); }}How Many TablesDescription:Today is Ignatius’ birthday. He invites a lot of friends. Now it’s dinner time. Ignatius wants to know how many tables he needs at least. You have to notice that not all the friends know each other, and all the friends do not want to stay with strangers.One important rule for this problem is that if I tell you A knows B, and B knows C, that means A, B, C know each other, so they can stay in one table.For example: If I tell you A knows B, B knows C, and D knows E, so A, B, C can stay in one table, and D, E have to stay in the other one. So Ignatius needs 2 tables at least.InputThe input starts with an integer T(1<=T<=25) which indicate the number of test cases. Then T test cases follow. Each test case starts with two integers N and M(1<=N,M<=1000). N indicates the number of friends, the friends are marked from 1 to N. Then M lines follow. Each line consists of two integers A and B(A!=B), that means friend A and friend B know each other. There will be a blank line between two cases.OutputFor each test case, just output how many tables Ignatius needs at least. Do NOT print any blanks.123456789101112Sample Input25 31 22 34 55 12 5Sample Output24code:123456789101112131415161718192021222324252627282930313233343536373839404142434445#include<stdio.h>#include<algorithm>#include<iostream>#include<queue>using namespace std;const int mod = 1e9;const int maxx = 1e5;int pre[maxx];int find(int x){ int r = x; while(pre[r] != r) { r = pre[r]; } return r;}void join(int x, int y){ int xx = find(x), yy = find(y); if(xx != yy) pre[xx] = yy;}int main(){ int n, m, T; int x, y; scanf("%d",&T); while(T --) { scanf("%d %d",&n, &m); for(int i = 1; i <= n; i ++) pre[i] = i; for(int i = 0; i < m; i ++) { scanf("%d %d",&x, &y); join(x, y); } int ans = 0; for(int i = 1; i <= n; i ++) if(pre[i] == i) ans ++; cout << ans << endl; } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
<tag>图论</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day16]]></title>
<url>%2F2019%2F08%2F03%2FDay16%2F</url>
<content type="text"><![CDATA[Day16今天是一场积分赛,还行~~OJ链接蚂蚁觅食(一)Description:一只饥饿的小蚂蚁外出觅食,幸运的小蚂蚁发现了好多食物,但是它只有一次搬食物的机会。可因为力气太小了,它不能搬走重量超过自己体重的食物,且只能搬走位置相邻的两个食物,或者只搬走其中一个。食物的位置不会改变。这可难住了这只蚂蚁,它不知道它最多能搬走多重的食物。请帮小蚂蚁计算。输入格式第一行一个正整数n,(n>=0并且n<=1000)第二行n个正整数 A[1]…..A[n],A[i] 表示在第i 个位置上食物的重量。A[i]<=1e9.第三行一个正整数m,表示蚂蚁的体重。(m<=1e9).输出格式一个整数表示小蚂蚁能带走的食物的重量。1234567样例input31 3 34output4code:12345678910111213141516171819#include<bits/stdc++.h>using namespace std;const int mod = 1e9;const int maxx = 1e5;int w[maxx], v[maxx], dp[maxx];int main(){ int N, V; cin >> N; for(int i = 1; i <= N; i ++) cin >> v[i]; cin >> V; for(int i = 1; i <= N; i ++) { for(int j = V; j >= v[i]; j --) dp[j] = max(dp[j], dp[j - v[i]] + v[i]); } cout << dp[V] << endl; return 0;}蚂蚁觅食(二)Description:一只饥饿的小蚂蚁外出觅食,幸运的的小蚂蚁发现了好多食物。但是这些食物位于一个N∗M的方格魔法阵的右下角,而小蚂蚁位于方格法阵的左上角。并且小蚂蚁被施展了魔法,它只能向下或者向右走。请你帮助小蚂蚁计算一下,它一共有多少条路可以走到有食物的方格。输入格式多组输入,每一组两个正整数N, M (N,M≤30)。表示一个方格魔法阵。输出格式一个整数表示一共有多少条路。12345样例input2 3output3code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465//dfs般写法#include<bits/stdc++.h>using namespace std;typedef long long ll;const int mod = 1e9;const int maxx = 1e5;int n, m;ll dp[50][50];int d[2][2] = {0, 1, 1, 0};ll dfs(int x, int y){ if(dp[x][y]) return dp[x][y]; for(int i = 0; i < 2; i ++) { int xx = x + d[i][0]; int yy = y + d[i][1]; if(xx >= 1 && yy >= 1 && xx <= n && yy <= m) dp[x][y] += dfs(xx, yy); } return dp[x][y];}int main(){ while(cin >> n >> m) { memset(dp, 0, sizeof dp); dp[n][m] = 1; cout << dfs(1, 1) << endl; } return 0;}//dp般写法#include<bits/stdc++.h>using namespace std;typedef long long ll;const int mod = 1e9 + 7;ll dp[1234][1234];ll n, m;int main(){ for(int i = 1; i < 1009; i ++) { dp[i][1] = 1; dp[1][i] = 1; } while(cin >> n >> m) { for(int i = 2; i <= n; i ++) { for(int j = 2; j <= m; j ++) { dp[i][j] = (dp[i - 1][j] + dp[i][j - 1]) % mod; } } cout << dp[n][m] << endl; } return 0;}蚂蚁觅食(三)Description:马上就要冬天了,勤劳的小蚂蚁需要储存足够多的食物才能安全过冬。今天,这只小蚂蚁走出巢穴寻找食物,但是这次蚁巢周围只有很少的食物,它需要去别的地方。不幸的是小蚂蚁的体力很有限,而且每走一个单位长度就要消耗一点体力,不能找的时间太久,所以想让你帮忙计算一下它是否能用剩下的体力把足够多的食物搬回蚁巢。由于蚂蚁的嘴太小,每次最多只能衔起一个食物。输入格式输入t组, t≤20第一行三个数n,E,V表示食物的个数,蚂蚁剩余的体力,安全过冬需要的最少食物体积, 0<n≤200,0<E,V≤10000。接下来n行,每行两个数pi,vi,表示第i个食物的位置和体积,0<p[i],v[i]≤1000。初始蚂蚁和蚁巢均在坐标轴原点。输出格式每个输出占一行。如果蚂蚁能安全过冬,输出 “YES”,否则输出”NO”。12345678910样例input21 2 21 21 2 22 1outputYESNOcode:12345678910111213141516171819202122232425#include<bits/stdc++.h>using namespace std;const int mod = 1e9;const int maxx = 1e5;int w[maxx], v[maxx], dp[maxx];int main(){ int t, n, E, V; cin >> t; while(t --) { memset(dp, 0, sizeof dp); cin >> n >> E >> V; for(int i = 1; i <= n; i ++) cin >> w[i] >> v[i]; for(int i = 1; i <= n; i ++) { for(int j = E / 2; j >= w[i]; j --) dp[j] = max(dp[j], dp[j - w[i]] + v[i]); } if(dp[E / 2] >= V) puts("YES"); else puts("NO"); } return 0;}##Description:平面上有 n只蚂蚁,它走过的路径可以看作一条直线由这n 条直线定义的某些区域是无界的,而另一些区域则是有界的。有界区域的最大个数是多少?比如现在有4条直线,只有下面最左边的图中直线定义的有界区域是最多的输入格式T 组输入, (1≤T≤100)每组一个数 n ,(1≤n≤109)输出格式对于每组数据,输出一个整数表示有界区域的最大个数。123456样例input14output3code:12345678910111213141516171819202122232425#include<bits/stdc++.h>using namespace std;typedef long long ll;const int mod = 1e9;const int maxx = 1e5;int main(){ int t; ll n; cin >> t; while(t --) { cin >> n; ll ans = 0; if(n < 3) ans = 0; else { ans = (n - 1) * (n - 2) / 2; } cout << ans << endl; } return 0;}蚂蚁和斐波那契Description:聪明的小蚂蚁最近学习了斐波那契数列,但是它想到了一个问题:从L到R之间斐波那契数列和的奇偶是什么呢?其中Fib[1]=1,Fib[2]=1 .输入格式单组输入:每组输入两个以空格隔开的数字 L 和 R其中 (0<L<=R<1018)输出格式从 L 到 R 斐波那契数列和的奇偶,如果是奇数输出 “1” (不带引号) ,否则输出 “0” (不带引号)12345样例input1 2output0code:1234567891011121314151617181920#include<bits/stdc++.h>using namespace std;typedef long long ll;ll ans[55];int main(){ ll mid,miid,l,r; cin>>l>>r; mid=l%3,miid=r%3; if(mid==0&&miid==0) puts("0"); else if(mid==miid) puts("1"); else if(mid==0&&miid==1) puts("1"); else if(mid==0&&miid==2) puts("0"); else if(mid==1&&miid==0) puts("0"); else if(mid==2&&miid==0) puts("1"); else if(mid==2&&miid==1) puts("0"); else if(mid==1&&miid==2) puts("0"); return 0;}蚂蚁装修Description:还有一个月就开学了,爱学习的小蚂蚁想庆祝一下!于是它要把它的“家”装修一下。首先要做的就是贴地板。小蚂蚁“家”的地面可以看成一个2∗N 的方格 ,它拥有无数块1∗2 和 2∗1的地板。请你帮下蚂蚁计算一下一共有多少种方法能把地面给放满 。地板不能切割,也不能重叠。输入格式单组输入:只有一个数字 N其中 (0<N<1018)输出格式输出放法数对109+7取模的结果123456789样例input2output2input1output1code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960#include<bits/stdc++.h>using namespace std;typedef long long ll;const int mod = 1e9 + 7;const int maxx = 4;struct node{ ll m[maxx][maxx];};node mul(node a, node b){ node ans; memset(ans.m, 0, sizeof ans.m); for(int i = 0; i < 2; i ++) { for(int j = 0; j < 2; j ++) { for(int k = 0; k < 2; k ++) ans.m[i][j] = (ans.m[i][j] + a.m[i][k] * b.m[k][j] % mod + mod) % mod; } } return ans;}node kpow(node a, ll b){ node res; memset(res.m, 0, sizeof res.m); for(int i = 0; i < 2; i ++) { res.m[i][i] = 1; } while(b) { if(b & 1) res = mul(res, a); b >>= 1; a = mul(a, a); } return res;}int main(){ ll n; cin >> n; node a, b, ans; a.m[0][0] = 2; a.m[0][1] = 0; a.m[1][0] = 1; a.m[1][1] = 0; b.m[0][0] = 1; b.m[0][1] = 1; b.m[1][0] = 1; b.m[1][1] = 0; if(n == 1) ans.m[0][0] = 1; else { ans = kpow(b, n - 2); ans = mul(ans, a); } cout << ans.m[0][0] << endl; return 0;}蚂蚁的镜像串Description:一只聪明的蚂蚁在学习了回文串之后,一直觉得回文串不够优美,所以它决定自己定义一种新的字符串——镜像串所谓镜像串,就是对一个字符串进行一整个完全的翻转后,得到的新字符串与原字符串相同,也就是说左右镜像之后的字符串和原串相同。例如:AA就是一个镜像串,bb不是镜像串现在给你一个字符串S,请你快速的判断字符串S是不是一个镜像串字符串中出现的字母字体如下表输入格式第一行一个整数T (1≤T≤100)代表有T组输入接下来T行,每行输入一个长度小于等于105的字符串S保证每个字符串只包含大小写字母输出格式对于每组输入,判断S是否为镜像串如果是,输出”YES”。否则输出”NO”。每组输出占一行12345678910111213141516样例input5QAQTAToUooVoXoXoutputNOYESYESYESYES提示mm,nn,uu也是镜像串code:123456789101112131415161718192021222324252627282930#include<bits/stdc++.h>using namespace std;int main(){ int t; string s; cin>>t; while(t--) { cin>>s; int flag=1; string mid=s; reverse(mid.begin(),mid.end()); for(int i=0;i<s.size();i++) { if((s[i]=='b'&&mid[i]=='d')||(s[i]=='d'&&mid[i]=='b')||(s[i]=='p'&&mid[i]=='q')||(s[i]=='q'&&mid[i]=='p')||(s[i]==mid[i]&&(s[i]=='A'||s[i]=='H'||s[i]=='I'||s[i]=='i'||s[i]=='l'||s[i]=='M'||s[i]=='m'||s[i]=='n'||s[i]=='O'||s[i]=='o'||s[i]=='T'||s[i]=='U'||s[i]=='u'||s[i]=='V'||s[i]=='v'||s[i]=='W'||s[i]=='w'||s[i]=='X'||s[i]=='x'||s[i]=='Y'))) { continue; } else { flag=0; break; } } if(flag==1) puts("YES"); else puts("NO"); }}蚂蚁赛跑Description:小白和小黑非常喜欢养蚂蚁,他们每个人都养了n只蚂蚁。有一天,他们想比一比谁养蚂蚁的本领更强,于是就举办了一场蚂蚁赛跑比赛。假设蚂蚁都是匀速直线奔跑。比赛的规则是这样的:每只蚂蚁必须且最多比一场,赢一场得10分,输一场扣10分。平局都不得分也不扣分。狡猾的小黑同学为了赢得比赛,提前偷到了小白所有蚂蚁得速度,请你帮小黑算一算,他在比赛中最多得多少分。输入格式有多组测试案例,最多有100组,对于每一组案例:第一行以正整数n ,(n≤1000),即每个人的蚂蚁数量。第二行的n个整数是小黑的蚂蚁的速度。第三行的n整数是小白的蚂蚁速度。蚂蚁的速度小于100输出格式对于每个输入案例,输出一个整数,这是小黑能够获得的最大分数。1234567891011样例input210 1010 10210 1100 8output00code:1待补蚂蚁上树Description:蚂蚁想知道这棵树上距离最远的两个点之间的距离给你一个具有 n 个节点的树求这棵树上距离最远的两个点之间的距离输入格式第一行一个整数 n ,(1≤n≤104)接下来 n−1 行,每行三个整数 x,y,z 表示 x 与 y 之间有一条长度为 z 的边 (1≤x,y≤n,1≤z≤104)输出格式一个整数表示树上距离最远的两个点之间的距离123456789样例input51 2 91 3 31 5 22 4 10output22code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162#include<bits/stdc++.h>using namespace std;const int mod = 1e9;const int maxx = 1e4 + 10;vector<pair<int, int> > v[maxx];bool vis[maxx];int dis[maxx];int ans, point;//struct node{// int x, y, step;//};void bfs(int x){ memset(vis, 0, sizeof vis); memset(dis, 0, sizeof dis); queue<int> q;// node e1, e2; q.push(x); vis[x] = 1; ans = 0; point = 0; while(!q.empty()) { int f = q.front(); q.pop(); if(dis[f] > ans) { ans = dis[f]; point = f;// return ans; } pair<int, int> t; for(int i = 0; i < v[f].size(); i ++) { t = v[f][i]; if(vis[t.first] == 0) { vis[t.first] = 1; dis[t.first] = t.second + dis[f]; q.push(t.first); } } }}int main(){ int n; int a, b, c; cin >> n; for(int i = 0; i < n - 1; i ++) { cin >> a >> b >> c; v[a].push_back(make_pair(b, c)); v[b].push_back(make_pair(a, c)); } bfs(1); bfs(point); cout << ans << endl; return 0;}蚂蚁的游戏Description:蚂蚁Bob和蚂蚁Alice是青梅竹蚁,Alice喜欢和Bob一起玩游戏,每当Alice想到新的游戏,都会找Bob一起玩今天Alice的游戏是这样的:n堆石子,两人轮流取。每次只能在1堆中取,不能不取,最先取完石子者胜Alice先取石子,Alice和Bob都非常聪明,拿石子的过程中不会出现失误。输入格式第一行有一个整数T,有T组输入数据(T≤50)每组第一行有一个数n表示有n堆石子,(1≤n≤20000)第二行有n个非零整数x,表示每堆石子的数量(x≤103)输出格式请你判断Alice能否在游戏中获胜,如果不能获胜,输出NO。否则,输出YES,并输出第一次取石子的所有方法(具体参见样例和提示)12345678910111213141516171819202122样例input2245 4555 7 8 9 10outputNOYES3 14 05 3提示对于第一组样例,不论Alice怎么取,Bob总能拿到最后一个石子,所以输出为NO对于第二组样例,Alice可以第一次取石子有三种取法:第3堆取出7个,剩下1个第4堆全部取出,剩下0个第5堆取出7个,剩下3个对于每组输出,总是按照堆的编号顺序输出的code:1待补]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day15]]></title>
<url>%2F2019%2F08%2F02%2FDay15%2F</url>
<content type="text"><![CDATA[Day15今天继续学习背包问题,刷题~刷题~刷题!OJ链接01背包Description:有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。第 i 件物品的体积是 vi,价值是 wi。求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。输入格式第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。输出格式输出一个整数,表示最大价值。数据范围0<N,V≤10000<vi,wi≤100012345678输入样例4 51 22 43 44 5输出样例:8code:123456789101112131415161718192021222324252627#include<bits/stdc++.h>using namespace std;int v[10001], w[10001];int dp[10001];int main(){ int N, V; cin >> N >> V; for(int i = 1; i <= N; i ++) { cin >> w[i] >> v[i]; } for(int i = 1; i <= N; i ++) { for(int j = V; j >= w[i]; j --) { dp[j] = max(dp[j], dp[j - w[i]] + v[i]);//下面的是没优化的部分// if(j >= w[i])// dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]);// else// dp[i][j] = dp[i - 1][j]; } } cout << dp[V]; return 0;}完全背包问题Description:有 N 种物品和一个容量是 V 的背包,每种物品都有无限件可用。第 i 种物品的体积是 vi,价值是 wi。求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。输入格式第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 种物品的体积和价值。输出格式输出一个整数,表示最大价值。数据范围0<N,V≤10000<vi,wi≤100012345678输入样例4 51 22 43 44 5输出样例:10code:123456789101112131415161718192021222324#include<bits/stdc++.h>using namespace std;int w[10001], v[10001];int dp[10001][10001];int main(){ int N, V; cin >> N >> V; for(int i = 1; i <= N; i ++) cin >> w[i] >> v[i]; for(int i = 1; i <= N; i ++) { for(int j = 0; j <= V; j ++) { if(j >= w[i]) dp[i][j] = max(dp[i - 1][j], dp[i][j - w[i]] + v[i]); else dp[i][j] = dp[i - 1][j]; } } cout << dp[N][V] << endl; return 0;}多重背包1Description:有 N 种物品和一个容量是 V 的背包。第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。输出最大价值。输入格式第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。输出格式输出一个整数,表示最大价值。数据范围0<N,V≤1000<vi,wi,si≤10012345678输入样例4 51 2 32 4 13 4 34 5 2输出样例:10code:123456789101112131415161718192021222324252627#include<bits/stdc++.h>using namespace std;const int f = 300;int w[f], v[f], c[f];int dp[f][f];int main(){ memset(dp, 0, sizeof dp); int N, V; cin >> N >> V; for(int i = 1; i <= N; i ++) cin >> w[i] >> v[i] >> c[i]; for(int i = 1; i <= N; i ++) { for(int j = V; j >= 0; j --) { //其实就是把这类物品展开,调用c[i]次01背包代码 for(int k = 0; k <= c[i]; k ++) { if(j >= w[i] * k) dp[i][j] = max(dp[i][j], dp[i - 1][j - w[i] * k] + v[i] * k); } } } cout << dp[N][V] << endl; return 0;}多重背包2(用二进制优化)Description:有 N 种物品和一个容量是 V 的背包。第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。输出最大价值。输入格式第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。输出格式输出一个整数,表示最大价值。数据范围0<N≤10000<V≤20000<vi,wi,si≤200012345678输入样例4 51 2 32 4 13 4 34 5 2输出样例:10code:12345678910111213141516171819202122232425262728293031323334#include<bits/stdc++.h>using namespace std;int w[1001], v[1001], c[1001], dp[2001];int a[25000], b[25000];int main(){ int N, V; cin >> N >> V; for(int i = 0; i < N; i ++) cin >> w[i] >> v[i] >> c[i]; int sum = 0; for(int i = 0; i < N; i ++) { for(int j = 1; j < c[i]; j <<= 1) { a[sum] = j * w[i];//存储容量 b[sum ++] = j * v[i];//存储价值 c[i] -= j; } if(c[i]) { a[sum] = c[i] * w[i]; b[sum ++] = c[i] * v[i]; } } for(int i = 0; i < sum; i ++) { for(int j = V; j >= a[i]; j --) dp[j] = max(dp[j], dp[j - a[i]] + b[i]); } cout << dp[V] << endl; return 0;}掺杂个字符串的题(混入其中)ISBN号码-字符串的题Description:每一本正式出版的图书都有一个ISBN号码与之对应,ISBN码包括99位数字、11位识别码和33位分隔符,其规定格式如x-xxx-xxxxx-x,其中符号-就是分隔符(键盘上的减号),最后一位是识别码,例如0-670-82162-4就是一个标准的ISBN码。ISBN码的首位数字表示书籍的出版语言,例如0代表英语;第一个分隔符-之后的三位数字代表出版社,例如670670代表维京出版社;第二个分隔符后的五位数字代表该书在该出版社的编号;最后一位为识别码。识别码的计算方法如下:首位数字乘以1加上次位数字乘以2……以此类推,用所得的结果mod 11,所得的余数即为识别码,如果余数为10,则识别码为大写字母X。例如ISBN号码0-670-82162-4中的识别码4是这样得到的:对067082162这9个数字,从左至右,分别乘以1,2,…,9再求和,即0×1+6×2+……+2×9=158,然后取158mod11的结果4作为识别码。你的任务是编写程序判断输入的ISBN号码中识别码是否正确,如果正确,则仅输出Right;如果错误,则输出你认为是正确的ISBN号码。输入格式一个字符序列,表示一本书的ISBN号码(保证输入符合ISBN号码的格式要求)。输出格式一行,假如输入的ISBN号码的识别码正确,那么输出Right,否则,按照规定的格式,输出正确的ISBN号码(包括分隔符-)。123456789输入输出样例输入0-670-82162-4输出Right输入0-670-82162-0输出0-670-82162-4code:1234567891011121314151617181920212223242526#include<bits/stdc++.h>using namespace std;int main(){ char str[13], a[12] = {"0123456789X"}; gets(str); int sum = 0; for(int i = 0, len = 1; i < 12; i ++) { if(str[i] == '-') continue; sum += (str[i] - '0') * len; len ++; } sum %= 11; if(a[sum] == str[12]) { puts("Right"); } else { str[12] = a[sum]; puts(str); } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
<tag>背包问题</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day14]]></title>
<url>%2F2019%2F08%2F01%2FDay14%2F</url>
<content type="text"><![CDATA[Day14今天讲的是矩阵快速幂相比于之前,算是好理解一点~递推式就比如FibFib[i] = Fib[i-1] + Fib[i-2]int Fib[maxn] ;Fib[1] = 1 ,Fib[2] = 1 ;for (int i = 3 ; i <= n ; i ++ ) {Fib[i] = Fib[i-1] + Fib[i-2] ;}矩阵快速幂链接矩阵的迹在线性代数中,一个n×n矩阵A的主对角线(从左上方至右下方的对角线)上各个元素的总和被称为矩阵A的迹(或迹数),一般记作tr(A)。FibonacciDescription:菲波那契数列是指这样的数列: 数列的第一个是0和第二个数是1,接下来每个数都等于前面2个数之和。 给出一个正整数a,要求菲波那契数列中第a个数的后四位是多少。Input多组数据 -1结束 范围1~10^9Output第x项的后4位1234567891011Sample Input099999999991000000000-1Sample Output0346266875code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxx = 1e5;const int mod = 10000;typedef long long ll;int N, M;int f = 2;struct node{ ll materix[101][101];};//矩阵乘法node mul(node a, node b){ node ans; memset(ans.materix, 0, sizeof ans.materix); for(ll i = 1; i <= f; i ++) { for(ll j = 1; j <= f; j ++) { for(ll k = 1; k <= f; k ++) { ans.materix[i][j] = (ans.materix[i][j] + a.materix[i][k] * b.materix[k][j] % mod) % mod; } } } return ans;}//矩阵快速幂node kpow(node a, int b){ node res; memset(res.materix, 0, sizeof res.materix); for(ll i = 1; i <= f; i ++) res.materix[i][i] = 1; while(b) { if(b & 1) res = mul(res, a); b >>= 1; a = mul(a, a); } return res;}int main(){ node ans, a, b; while(~scanf("%d",&N)) { if(N == -1) break; if(N == 0) { puts("0"); continue; } a.materix[1][1] = 1 ; a.materix[1][2] = 0 ; a.materix[2][1] = 1 ; a.materix[2][2] = 0 ; b.materix[1][1] = 1 ; b.materix[1][2] = 1 ; b.materix[2][1] = 1 ; b.materix[2][2] = 0 ; ans = kpow(b, N - 2); ans = mul(ans, a); cout << ans.materix[1][1] % 10000 << endl;; } return 0;}Tr AA为一个方阵,则Tr A表示A的迹(就是主对角线上各项的和),现要求Tr(A^k)%9973。Input数据的第一行是一个T,表示有T组数据。每组数据的第一行有n(2 <= n <= 10)和k(2 <= k < 10^9)两个数据。接下来有n行,每行有n个数据,每个数据的范围是[0,9],表示方阵A的内容。Output对应每组数据,输出Tr(A^k)%9973。123456789101112Sample Input22 21 00 13 999999991 2 34 5 67 8 9Sample Output22686code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxx = 1e5;const int mod = 9973;typedef long long ll;ll N, M;struct node{ ll materix[101][101];};//矩阵乘法node mul(node a, node b){ node ans; memset(ans.materix, 0, sizeof ans.materix); for(int i = 1; i <= N; i ++) { for(int j = 1; j <= N; j ++) { for(int k = 1; k <= N; k ++) { ans.materix[i][j] = (ans.materix[i][j] + a.materix[i][k] * b.materix[k][j]) % mod; } } } return ans;}//矩阵快速幂node kpow(node a, int b){ node res; memset(res.materix, 0, sizeof res.materix); for(int i = 1; i <= N; i ++) res.materix[i][i] = 1; while(b) { if(b & 1) res = mul(res, a); b >>= 1; a = mul(a, a); } return res;}int main(){ node ans, b; int T; cin >> T; ll sum; while(T --) { sum = 0; cin >> N >> M; for(int i = 1; i <= N; i ++) { for(int j = 1; j <= N; j ++) cin >> b.materix[i][j]; } ans = kpow(b, M - 1); ans = mul(ans, b); for(int i = 1; i <= N; i ++) { sum = (sum + ans.materix[i][i]) % mod; } cout << sum << endl; } return 0;}A Simple Math ProblemDescription:Lele now is thinking about a simple function f(x).If x < 10 f(x) = x.If x >= 10 f(x) = a0 f(x-1) + a1 f(x-2) + a2 f(x-3) + …… + a9 f(x-10);And ai(0<=i<=9) can only be 0 or 1 .Now, I will give a0 ~ a9 and two positive integers k and m ,and could you help Lele to caculate f(k)%m.InputThe problem contains mutiple test cases.Please process to the end of file.In each case, there will be two lines.In the first line , there are two positive integers k and m. ( k<2*10^9 , m < 10^5 )In the second line , there are ten integers represent a0 ~ a9.OutputFor each case, output f(k) % m in one line.12345678Sample Input10 99991 1 1 1 1 1 1 1 1 120 5001 0 1 0 1 0 1 0 1 0Sample Output45104code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxx = 1e5;const int mod = 1e9;int m;int f = 10;int x[10];struct node{ int materix[10][10];};//矩阵乘法node mul(node a, node b){ node ans; memset(ans.materix, 0, sizeof ans.materix); for(int i = 0; i < f; i ++) { for(int j = 0; j < f; j ++) { for(int k = 0; k < f; k ++) ans.materix[i][j] = (ans.materix[i][j] + a.materix[i][k] * b.materix[k][j] % m) % m; } } return ans;}//矩阵快速幂node kpow(node a, int b){ node res; memset(res.materix, 0, sizeof res.materix); for(int i = 0; i < f; i ++) res.materix[i][i] = 1; while(b) { if(b & 1) res = mul(res, a); b >>= 1; a = mul(a, a); } return res;}int main(){ node ans, a, b, s; int n; while(~scanf("%d %d",&n, &m)) { for(int i = 0; i < f; i ++) cin >> x[i]; if(n < 10) ans.materix[0][0] = n % m; else { memset(a.materix, 0, sizeof a.materix); memset(b.materix, 0, sizeof b.materix); for(int i = 0; i < f; i ++) { a.materix[i][0] = 10 - 1 - i; b.materix[0][i] = x[i]; } for(int i = 1; i < 10; i ++) b.materix[i][i - 1] = 1; ans = kpow(b, n - 9); ans = mul(ans, a); } cout << ans.materix[0][0] << endl; } return 0;}Recursive sequenceDescription:Farmer John likes to play mathematics games with his N cows. Recently, they are attracted by recursive sequences. In each turn, the cows would stand in a line, while John writes two positive numbers a and b on a blackboard. And then, the cows would say their identity number one by one. The first cow says the first number a and the second says the second number b. After that, the i-th cow says the sum of twice the (i-2)-th number, the (i-1)-th number, and i4. Now, you need to write a program to calculate the number of the N-th cow in order to check if John’s cows can make it right.InputThe first line of input contains an integer t, the number of test cases. t test cases follow.Each case contains only one line with three numbers N, a and b where N,a,b < 231 as described above.OutputFor each test case, output the number of the N-th cow. This number might be very large, so you need to output it modulo 2147493647.1234567891011Sample Input23 1 24 1 10Sample Output85369HintIn the first case, the third number is 85 = 2*1十2十3^4. In the second case, the third number is 93 = 2*1十1*10十3^4 and the fourth number is 369 = 2 * 10 十 93 十 4^4.code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxx = 1e5;typedef long long ll;const ll mod = 2147493647;const ll f = 7;ll n, x, y;struct node{ ll materix[f][f];};//矩阵乘法node mul(node a, node b){ node ans; memset(ans.materix, 0, sizeof ans.materix); for(int i = 0; i < f; i ++) { for(int j = 0; j < f; j ++) { for(int k = 0; k < f; k ++) ans.materix[i][j] = (ans.materix[i][j] + a.materix[i][k] * b.materix[k][j] % mod + mod) % mod; } } return ans; }//矩阵快速幂node kpow(node a, ll b){ node res; memset(res.materix, 0, sizeof res.materix); for(int i = 0; i < 7; i ++) for(int j = 0; j < 7; j ++) { if(i == j) res.materix[i][j] = 1; } while(b) { if(b & 1) res = mul(res, a); b >>= 1; a = mul(a, a); } return res;}int main(){ ll T; node a, b, ans; cin >> T; while(T --) { cin >> n >> x >> y; if(n == 1) { cout << x << endl; } else if(n == 2) { cout << y << endl; } else { memset(a.materix, 0, sizeof a.materix); memset(b.materix, 0, sizeof b.materix); a.materix[0][0]=1,a.materix[0][1]=2,a.materix[0][2]=1,a.materix[0][3]=0,a.materix[0][4]=0,a.materix[0][5]=0;a.materix[0][6]=0; a.materix[1][0]=1,a.materix[1][1]=0,a.materix[1][2]=0,a.materix[1][3]=0,a.materix[1][4]=0,a.materix[1][5]=0;a.materix[1][6]=0; a.materix[2][0]=0,a.materix[2][1]=0,a.materix[2][2]=1,a.materix[2][3]=4,a.materix[2][4]=6,a.materix[2][5]=4;a.materix[2][6]=1; a.materix[3][0]=0,a.materix[3][1]=0,a.materix[3][2]=0,a.materix[3][3]=1,a.materix[3][4]=3,a.materix[3][5]=3;a.materix[3][6]=1; a.materix[4][0]=0,a.materix[4][1]=0,a.materix[4][2]=0,a.materix[4][3]=0,a.materix[4][4]=1,a.materix[4][5]=2;a.materix[4][6]=1; a.materix[5][0]=0,a.materix[5][1]=0,a.materix[5][2]=0,a.materix[5][3]=0,a.materix[5][4]=0,a.materix[5][5]=1;a.materix[5][6]=1; a.materix[6][0]=0,a.materix[6][1]=0,a.materix[6][2]=0,a.materix[6][3]=0,a.materix[6][4]=0,a.materix[6][5]=0;a.materix[6][6]=1; b.materix[0][0]=y % mod; b.materix[1][0]=x % mod; b.materix[2][0]=81; b.materix[3][0]=27; b.materix[4][0]=9; b.materix[5][0]=3; b.materix[6][0]=1; ans = kpow(a, n - 2); ans = mul(ans, b); cout << ans.materix[0][0] << endl; } } return 0;}求递推序列的第N项有一个序列是这样定义的:f(1) = 1, f(2) = 1, f(n) = (A f(n - 1) + B f(n - 2)) mod 7.给出A,B和N,求f(n)的值。输入输入3个数:A,B,N。数字之间用空格分割。(-10000 <= A, B <= 10000, 1 <= N <= 10^9)输出输出f(n)的值。1234输入样例3 -1 5输出样例6code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxx = 1e5;int f = 2;const int mod = 7;struct node{ int materix[5][5];};//矩阵乘法node nul(node a, node b){ node ans; memset(ans.materix, 0, sizeof ans.materix); for(int i = 1; i <= f; i ++) { for(int j = 1; j <= f; j ++) { for(int k = 1; k <= f; k ++) ans.materix[i][j] = (ans.materix[i][j] + a.materix[i][k] * b.materix[k][j] % mod + mod) % mod; } } return ans;}//矩阵快速幂node kpow(node a, int b){ node res; memset(res.materix, 0, sizeof res.materix); for(int i = 1; i <= f ;i ++) res.materix[i][i] = 1; while(b) { if(b & 1) res = nul(res, a); b >>= 1; a = nul(a, a); } return res;}int main(){ int A, B, N; cin >> A >> B >> N; node a, b; if(N == 1 || N == 1) puts("1"); else { a.materix[1][1] = 1; a.materix[1][2] = 0; a.materix[2][1] = 1; a.materix[2][2] = 0; b.materix[1][1] = A; b.materix[1][2] = B; b.materix[2][1] = 1; b.materix[2][2] = 0; node ans = kpow(b, N - 2); ans = nul(ans, a); cout << ans.materix[1][1] << endl; } return 0;}矩阵快速幂Description:给出一个N N的矩阵,其中的元素均为正整数。求这个矩阵的M次方。由于M次方的计算结果太大,只需要输出每个元素Mod (10^9 + 7)的结果。输入第1行:2个数N和M,中间用空格分隔。N为矩阵的大小,M为M次方。(2 <= N <= 100, 1 <= M <= 10^9)第2 - N + 1行:每行N个数,对应N N矩阵中的1行。(0 <= N[i] <= 10^9)输出共N行,每行N个数,对应M次方Mod (10^9 + 7)的结果。1234567输入样例2 31 11 1输出样例4 44 4code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxx = 1e5;const int mod = 1e9 + 7;typedef long long ll;int N, M;struct node{ ll materix[101][101];};//矩阵乘法node mul(node a, node b){ node ans; memset(ans.materix, 0, sizeof ans.materix); for(int i = 1; i <= N; i ++) { for(int j = 1; j <= N; j ++) { for(int k = 1; k <= N; k ++) { ans.materix[i][j] = (ans.materix[i][j] + a.materix[i][k] * b.materix[k][j]) % mod; } } } return ans;}//矩阵快速幂node kpow(node a, int b){ node res; for(int i = 1; i <= N; i ++) res.materix[i][i] = 1; while(b) { if(b & 1) res = mul(res, a); b >>= 1; a = mul(a, a); } return res;}int main(){ node ans, b; cin >> N >> M; for(int i = 1; i <= N; i ++) { for(int j = 1; j <= N; j ++) cin >> b.materix[i][j]; } ans = kpow(b, M - 1); ans = mul(ans, b); for(int i = 1; i <= N; i ++) { for(int j = 1; j <= N; j ++) cout << ans.materix[i][j] << " "; puts(""); } return 0;}矩阵乘法Description:给出2个N N的矩阵M1和M2,输出2个矩阵相乘后的结果。输入第1行:1个数N,表示矩阵的大小(2 <= N <= 100)第2 - N + 1行,每行N个数,对应M1的1行(0 <= M1[i] <= 1000)第N + 2 - 2N + 1行,每行N个数,对应M2的1行(0 <= M2[i] <= 1000)输出输出共N行,每行N个数,对应M1 M2的结果的一行。123456789输入样例21 00 10 11 0输出样例0 11 0code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxx = 1e5;const int mod = 1e9 + 7;typedef long long ll;int N, M;struct node{ ll materix[101][101];};//矩阵乘法node mul(node a, node b){ node ans; memset(ans.materix, 0, sizeof ans.materix); for(int i = 1; i <= N; i ++) { for(int j = 1; j <= N; j ++) { for(int k = 1; k <= N; k ++) { ans.materix[i][j] = (ans.materix[i][j] + a.materix[i][k] * b.materix[k][j]) % mod; } } } return ans;}int main(){ node ans, a, b; cin >> N; for(int i = 1; i <= N; i ++) { for(int j = 1; j <= N; j ++) cin >> a.materix[i][j]; } for(int i = 1; i <= N; i ++) { for(int j = 1; j <= N; j ++) cin >> b.materix[i][j]; } ans = mul(a, b); for(int i = 1; i <= N; i ++) { for(int j = 1; j <= N; j ++) cout << ans.materix[i][j] << " "; puts(""); } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
<tag>矩阵快速幂</tag>
</tags>
</entry>
<entry>
<title><![CDATA[背包九讲]]></title>
<url>%2F2019%2F07%2F31%2F%E8%83%8C%E5%8C%85%E4%B9%9D%E8%AE%B2%2F</url>
<content type="text"><![CDATA[背包九讲学习背包问题,肯定是要学习背包就讲的,这篇就整理一个全一点的背包九讲背包问题在实际问题中还是比较重要的记录下来问题多多复习争取熟练掌握以下内容皆是参考的别人的博客内容整理而成P01: 01背包问题12345678910111213141516171819202122232425题目 有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 基本思路 这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。 用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}。 这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。所以有必要将它详细解释一下:“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”;如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f [i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。 注意f[i][v]有意义当且仅当存在一个前i件物品的子集,其费用总和为v。所以按照这个方程递推完毕后,最终的答案并不一定是f[N] [V],而是f[N][0..V]的最大值。如果将状态的定义中的“恰”字去掉,在转移方程中就要再加入一项f[i][v-1],这样就可以保证f[N] [V]就是最后的答案。至于为什么这样就可以,由你自己来体会了。 优化空间复杂度 以上方法的时间和空间复杂度均为O(N*V),其中时间复杂度基本已经不能再优化了,但空间复杂度却可以优化到O(V)。 先考虑上面讲的基本思路如何实现,肯定是有一个主循环i=1..N,每次算出来二维数组f[i][0..V]的所有值。那么,如果只用一个数组f [0..V],能不能保证第i次循环结束后f[v]中表示的就是我们定义的状态f[i][v]呢?f[i][v]是由f[i-1][v]和f[i-1] [v-c[i]]两个子问题递推而来,能否保证在推f[i][v]时(也即在第i次主循环中推f[v]时)能够得到f[i-1][v]和f[i-1][v -c[i]]的值呢?事实上,这要求在每次主循环中我们以v=V..0的顺序推f[v],这样才能保证推f[v]时f[v-c[i]]保存的是状态f[i -1][v-c[i]]的值。伪代码如下: for i=1..N for v=V..0 f[v]=max{f[v],f[v-c[i]]+w[i]}; 其中的f[v]=max{f[v],f[v-c[i]]}一句恰就相当于我们的转移方程f[i][v]=max{f[i-1][v],f[i- 1][v-c[i]]},因为现在的f[v-c[i]]就相当于原来的f[i-1][v-c[i]]。如果将v的循环顺序从上面的逆序改成顺序的话,那么则成了f[i][v]由f[i][v-c[i]]推知,与本题意不符,但它却是另一个重要的背包问题P02最简捷的解决方案,故学习只用一维数组解01背包问题是十分必要的。 总结 01背包问题是最基本的背包问题,它包含了背包问题中设计状态、方程的最基本思想,另外,别的类型的背包问题往往也可以转换成01背包问题求解。故一定要仔细体会上面基本思路的得出方法,状态转移方程的意义,以及最后怎样优化的空间复杂度。P02: 完全背包问题123456789101112131415161718192021222324题目 有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 基本思路 这个问题非常类似于01背包问题,所不同的是每种物品有无限件。也就是从每种物品的角度考虑,与它相关的策略已并非取或不取两种,而是有取0件、取1件、取2件……等很多种。如果仍然按照解01背包时的思路,令f[i][v]表示前i种物品恰放入一个容量为v的背包的最大权值。仍然可以按照每种物品不同的策略写出状态转移方程,像这样:f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k*c[i]<= v}。这跟01背包问题一样有O(N*V)个状态需要求解,但求解每个状态的时间则不是常数了,求解状态f[i][v]的时间是O(v/c[i]),总的复杂度是超过O(VN)的。 将01背包问题的基本思路加以改进,得到了这样一个清晰的方法。这说明01背包问题的方程的确是很重要,可以推及其它类型的背包问题。但我们还是试图改进这个复杂度。 一个简单有效的优化 完全背包问题有一个很简单有效的优化,是这样的:若两件物品i、j满足c[i]<=c[j]且w[i]>=w[j],则将物品j去掉,不用考虑。这个优化的正确性显然:任何情况下都可将价值小费用高得j换成物美价廉的i,得到至少不会更差的方案。对于随机生成的数据,这个方法往往会大大减少物品的件数,从而加快速度。然而这个并不能改善最坏情况的复杂度,因为有可能特别设计的数据可以一件物品也去不掉。 转化为01背包问题求解 既然01背包问题是最基本的背包问题,那么我们可以考虑把完全背包问题转化为01背包问题来解。最简单的想法是,考虑到第i种物品最多选V/c [i]件,于是可以把第i种物品转化为V/c[i]件费用及价值均不变的物品,然后求解这个01背包问题。这样完全没有改进基本思路的时间复杂度,但这毕竟给了我们将完全背包问题转化为01背包问题的思路:将一种物品拆成多件物品。 更高效的转化方法是:把第i种物品拆成费用为c[i]*2^k、价值为w[i]*2^k的若干件物品,其中k满足c[i]*2^k<V。这是二进制的思想,因为不管最优策略选几件第i种物品,总可以表示成若干个2^k件物品的和。这样把每种物品拆成O(log(V/c[i]))件物品,是一个很大的改进。但我们有更优的O(VN)的算法。 * O(VN)的算法这个算法使用一维数组,先看伪代码: <pre class"example"> for i=1..N for v=0..V f[v]=max{f[v],f[v-c[i]]+w[i]}; 你会发现,这个伪代码与P01的伪代码只有v的循环次序不同而已。为什么这样一改就可行呢?首先想想为什么P01中要按照v=V..0的逆序来循环。这是因为要保证第i次循环中的状态f[i][v]是由状态f[i-1][v-c[i]]递推而来。换句话说,这正是为了保证每件物品只选一次,保证在考虑“选入第i件物品”这件策略时,依据的是一个绝无已经选入第i件物品的子结果f[i-1][v-c[i]]。而现在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第i种物品”这种策略时,却正需要一个可能已选入第i种物品的子结果f[i][v-c[i]],所以就可以并且必须采用v= 0..V的顺序循环。这就是这个简单的程序为何成立的道理。 这个算法也可以以另外的思路得出。例如,基本思路中的状态转移方程可以等价地变形成这种形式:f[i][v]=max{f[i-1][v],f[i][v-c[i]]+w[i]},将这个方程用一维数组实现,便得到了上面的伪代码。 总结 完全背包问题也是一个相当基础的背包问题,它有两个状态转移方程,分别在“基本思路”以及“O(VN)的算法“的小节中给出。希望你能够对这两个状态转移方程都仔细地体会,不仅记住,也要弄明白它们是怎么得出来的,最好能够自己想一种得到这些方程的方法。事实上,对每一道动态规划题目都思考其方程的意义以及如何得来,是加深对动态规划的理解、提高动态规划功力的好方法。P03: 多重背包问题12345678910111213141516171819202122题目 有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 基本算法 这题目和完全背包问题很类似。基本的方程只需将完全背包问题的方程略微一改即可,因为对于第i种物品有n[i]+1种策略:取0件,取1件……取 n[i]件。令f[i][v]表示前i种物品恰放入一个容量为v的背包的最大权值,则:f[i][v]=max{f[i-1][v-k*c[i]]+ k*w[i]|0<=k<=n[i]}。复杂度是O(V*∑n[i])。 转化为01背包问题 另一种好想好写的基本方法是转化为01背包求解:把第i种物品换成n[i]件01背包中的物品,则得到了物品数为∑n[i]的01背包问题,直接求解,复杂度仍然是O(V*∑n[i])。 但是我们期望将它转化为01背包问题之后能够像完全背包一样降低复杂度。仍然考虑二进制的思想,我们考虑把第i种物品换成若干件物品,使得原问题中第i种物品可取的每种策略——取0..n[i]件——均能等价于取若干件代换以后的物品。另外,取超过n[i]件的策略必不能出现。 方法是:将第i种物品分成若干件物品,其中每件物品有一个系数,这件物品的费用和价值均是原来的费用和价值乘以这个系数。使这些系数分别为 1,2,4,...,2^(k-1),n[i]-2^k+1,且k是满足n[i]-2^k+1>0的最大整数。例如,如果n[i]为13,就将这种物品分成系数分别为1,2,4,6的四件物品。 分成的这几件物品的系数和为n[i],表明不可能取多于n[i]件的第i种物品。另外这种方法也能保证对于0..n[i]间的每一个整数,均可以用若干个系数的和表示,这个证明可以分0..2^k-1和2^k..n[i]两段来分别讨论得出,并不难,希望你自己思考尝试一下。 这样就将第i种物品分成了O(log n[i])种物品,将原问题转化为了复杂度为O(V*∑log n[i])的01背包问题,是很大的改进。 O(VN)的算法 多重背包问题同样有O(VN)的算法。这个算法基于基本算法的状态转移方程,但应用单调队列的方法使每个状态的值可以以均摊O(1)的时间求解。由于用单调队列优化的DP已超出了NOIP的范围,故本文不再展开讲解。我最初了解到这个方法是在楼天成的“男人八题”幻灯片上。 小结 这里我们看到了将一个算法的复杂度由O(V*∑n[i])改进到O(V*∑log n[i])的过程,还知道了存在应用超出NOIP范围的知识的O(VN)算法。希望你特别注意“拆分物品”的思想和方法,自己证明一下它的正确性,并用尽量简洁的程序来实现。P04: 混合三种背包问题12345678910111213141516171819问题 如果将P01、P02、P03混合起来。也就是说,有的物品只可以取一次(01背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包)。应该怎么求解呢? 01背包与完全背包的混合 考虑到在P01和P02中最后给出的伪代码只有一处不同,故如果只有两类物品:一类物品只能取一次,另一类物品可以取无限次,那么只需在对每个物品应用转移方程时,根据物品的类别选用顺序或逆序的循环即可,复杂度是O(VN)。伪代码如下: for i=1..N if 第i件物品是01背包 for v=V..0 f[v]=max{f[v],f[v-c[i]]+w[i]}; else if 第i件物品是完全背包 for v=0..V f[v]=max{f[v],f[v-c[i]]+w[i]}; 再加上多重背包 如果再加上有的物品最多可以取有限次,那么原则上也可以给出O(VN)的解法:遇到多重背包类型的物品用单调队列解即可。但如果不考虑超过NOIP范围的算法的话,用P03中将每个这类物品分成O(log n[i])个01背包的物品的方法也已经很优了。 小结 有人说,困难的题目都是由简单的题目叠加而来的。这句话是否公理暂且存之不论,但它在本讲中已经得到了充分的体现。本来01背包、完全背包、多重背包都不是什么难题,但将它们简单地组合起来以后就得到了这样一道一定能吓倒不少人的题目。但只要基础扎实,领会三种基本背包问题的思想,就可以做到把困难的题目拆分成简单的题目来解决。P05: 二维费用的背包问题12345678910111213问题 二维费用的背包问题是指:对于每件物品,具有两种不同的费用;选择这件物品必须同时付出这两种代价;对于每种代价都有一个可付出的最大值(背包容量)。问怎样选择物品可以得到最大的价值。设这两种代价分别为代价1和代价2,第i件物品所需的两种代价分别为a[i]和b[i]。两种代价可付出的最大值(两种背包容量)分别为V和U。物品的价值为w[i]。 算法 费用加了一维,只需状态也加一维即可。设f[i][v][u]表示前i件物品付出两种代价分别为v和u时可获得的最大价值。状态转移方程就是:f [i][v][u]=max{f[i-1][v][u],f[i-1][v-a[i]][u-b[i]]+w[i]}。如前述方法,可以只使用二维的数组:当每件物品只可以取一次时变量v和u采用顺序的循环,当物品有如完全背包问题时采用逆序的循环。当物品有如多重背包问题时拆分物品。 物品总个数的限制 有时,“二维费用”的条件是以这样一种隐含的方式给出的:最多只能取M件物品。这事实上相当于每件物品多了一种“件数”的费用,每个物品的件数费用均为1,可以付出的最大件数费用为M。换句话说,设f[v][m]表示付出费用v、最多选m件时可得到的最大价值,则根据物品的类型(01、完全、多重)用不同的方法循环更新,最后在f[0..V][0..M]范围内寻找答案。 另外,如果要求“恰取M件物品”,则在f[0..V][M]范围内寻找答案。 小结 事实上,当发现由熟悉的动态规划题目变形得来的题目时,在原来的状态中加一纬以满足新的限制是一种比较通用的方法。希望你能从本讲中初步体会到这种方法。P06: 分组的背包问题1234567891011121314151617问题 有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 算法 这个问题变成了每组物品有若干种策略:是选择本组的某一件,还是一件都不选。也就是说设f[k][v]表示前k组物品花费费用v能取得的最大权值,则有f[k][v]=max{f[k-1][v],f[k-1][v-c[i]]+w[i]|物品i属于第k组}。 使用一维数组的伪代码如下: for 所有的组k for 所有的i属于组k for v=V..0 f[v]=max{f[v],f[v-c[i]]+w[i]} 另外,显然可以对每组中的物品应用P02中“一个简单有效的优化”。 小结 分组的背包问题将彼此互斥的若干物品称为一个组,这建立了一个很好的模型。不少背包问题的变形都可以转化为分组的背包问题(例如P07),由分组的背包问题进一步可定义“泛化物品”的概念,十分有利于解题。P07: 有依赖的背包问题1234567891011121314151617181920212223简化的问题 这种背包问题的物品间存在某种“依赖”的关系。也就是说,i依赖于j,表示若选物品i,则必须选物品j。为了简化起见,我们先设没有某个物品既依赖于别的物品,又被别的物品所依赖;另外,没有某件物品同时依赖多件物品。 算法 这个问题由NOIP2006金明的预算方案一题扩展而来。遵从该题的提法,将不依赖于别的物品的物品称为“主件”,依赖于某主件的物品称为“附件”。由这个问题的简化条件可知所有的物品由若干主件和依赖于每个主件的一个附件集合组成。 按照背包问题的一般思路,仅考虑一个主件和它的附件集合。可是,可用的策略非常多,包括:一个也不选,仅选择主件,选择主件后再选择一个附件,选择主件后再选择两个附件……无法用状态转移方程来表示如此多的策略。(事实上,设有n个附件,则策略有2^n+1个,为指数级。) 考虑到所有这些策略都是互斥的(也就是说,你只能选择一种策略),所以一个主件和它的附件集合实际上对应于P06中的一个物品组,每个选择了主件又选择了若干个附件的策略对应于这个物品组中的一个物品,其费用和价值都是这个策略中的物品的值的和。但仅仅是这一步转化并不能给出一个好的算法,因为物品组中的物品还是像原问题的策略一样多。 再考虑P06中的一句话:可以对每组中的物品应用P02中“一个简单有效的优化”。这提示我们,对于一个物品组中的物品,所有费用相同的物品只留一个价值最大的,不影响结果。所以,我们可以对主件i的“附件集合”先进行一次01背包,得到费用依次为0..V-c[i]所有这些值时相应的最大价值f'[0..V-c[i]]。那么这个主件及它的附件集合相当于V-c[i]+1个物品的物品组,其中费用为c[i]+k的物品的价值为f'[k]+w[i]。也就是说原来指数级的策略中有很多策略都是冗余的,通过一次01背包后,将主件i转化为 V-c[i]+1个物品的物品组,就可以直接应用P06的算法解决问题了。 更一般的问题 更一般的问题是:依赖关系以图论中“森林”的形式给出(森林即多叉树的集合),也就是说,主件的附件仍然可以具有自己的附件集合,限制只是每个物品最多只依赖于一个物品(只有一个主件)且不出现循环依赖。 解决这个问题仍然可以用将每个主件及其附件集合转化为物品组的方式。唯一不同的是,由于附件可能还有附件,就不能将每个附件都看作一个一般的01 背包中的物品了。若这个附件也有附件集合,则它必定要被先转化为物品组,然后用分组的背包问题解出主件及其附件集合所对应的附件组中各个费用的附件所对应的价值。 事实上,这是一种树形DP,其特点是每个父节点都需要对它的各个儿子的属性进行一次DP以求得自己的相关属性。这已经触及到了“泛化物品”的思想。看完P08后,你会发现这个“依赖关系树”每一个子树都等价于一件泛化物品,求某节点为根的子树对应的泛化物品相当于求其所有儿子的对应的泛化物品之和。 小结 NOIP2006的那道背包问题我做得很失败,写了上百行的代码,却一分未得。后来我通过思考发现通过引入“物品组”和“依赖”的概念可以加深对这题的理解,还可以解决它的推广问题。用物品组的思想考虑那题中极其特殊的依赖关系:物品不能既作主件又作附件,每个主件最多有两个附件,可以发现一个主件和它的两个附件等价于一个由四个物品组成的物品组,这便揭示了问题的某种本质。 我想说:失败不是什么丢人的事情,从失败中全无收获才是。P08: 泛化物品123456789101112131415161718192021222324252627定义 考虑这样一种物品,它并没有固定的费用和价值,而是它的价值随着你分配给它的费用而变化。这就是泛化物品的概念。 更严格的定义之。在背包容量为V的背包问题中,泛化物品是一个定义域为0..V中的整数的函数h,当分配给它的费用为v时,能得到的价值就是h(v)。 这个定义有一点点抽象,另一种理解是一个泛化物品就是一个数组h[0..V],给它费用v,可得到价值h[V]。 一个费用为c价值为w的物品,如果它是01背包中的物品,那么把它看成泛化物品,它就是除了h(c)=w其它函数值都为0的一个函数。如果它是完全背包中的物品,那么它可以看成这样一个函数,仅当v被c整除时有h(v)=v/c*w,其它函数值均为0。如果它是多重背包中重复次数最多为n的物品,那么它对应的泛化物品的函数有h(v)=v/c*w仅当v被c整除且v/c<=n,其它情况函数值均为0。 一个物品组可以看作一个泛化物品h。对于一个0..V中的v,若物品组中不存在费用为v的的物品,则h(v)=0,否则h(v)为所有费用为v的物品的最大价值。P07中每个主件及其附件集合等价于一个物品组,自然也可看作一个泛化物品。 泛化物品的和 如果面对两个泛化物品h和l,要用给定的费用从这两个泛化物品中得到最大的价值,怎么求呢?事实上,对于一个给定的费用v,只需枚举将这个费用如何分配给两个泛化物品就可以了。同样的,对于0..V的每一个整数v,可以求得费用v分配到h和l中的最大价值f(v)。也即f(v)=max{h(k) +l(v-k)|0<=k<=v}。可以看到,f也是一个由泛化物品h和l决定的定义域为0..V的函数,也就是说,f是一个由泛化物品h和 l决定的泛化物品。 由此可以定义泛化物品的和:h、l都是泛化物品,若泛化物品f满足f(v)=max{h(k)+l(v-k)|0<=k<=v},则称f是h与l的和,即f=h+l。这个运算的时间复杂度是O(V^2)。 泛化物品的定义表明:在一个背包问题中,若将两个泛化物品代以它们的和,不影响问题的答案。事实上,对于其中的物品都是泛化物品的背包问题,求它的答案的过程也就是求所有这些泛化物品之和的过程。设此和为s,则答案就是s[0..V]中的最大值。 背包问题的泛化物品 一个背包问题中,可能会给出很多条件,包括每种物品的费用、价值等属性,物品之间的分组、依赖等关系等。但肯定能将问题对应于某个泛化物品。也就是说,给定了所有条件以后,就可以对每个非负整数v求得:若背包容量为v,将物品装入背包可得到的最大价值是多少,这可以认为是定义在非负整数集上的一件泛化物品。这个泛化物品——或者说问题所对应的一个定义域为非负整数的函数——包含了关于问题本身的高度浓缩的信息。一般而言,求得这个泛化物品的一个子域(例如0..V)的值之后,就可以根据这个函数的取值得到背包问题的最终答案。 综上所述,一般而言,求解背包问题,即求解这个问题所对应的一个函数,即该问题的泛化物品。而求解某个泛化物品的一种方法就是将它表示为若干泛化物品的和然后求之。 小结 本讲可以说都是我自己的原创思想。具体来说,是我在学习函数式编程的 Scheme 语言时,用函数编程的眼光审视各类背包问题得出的理论。这一讲真的很抽象,也许在“模型的抽象程度”这一方面已经超出了NOIP的要求,所以暂且看不懂也没关系。相信随着你的OI之路逐渐延伸,有一天你会理解的。 我想说:“思考”是一个OIer最重要的品质。简单的问题,深入思考以后,也能发现更多。P09: 背包问题问法的变化1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556以上涉及的各种背包问题都是要求在背包容量(费用)的限制下求可以取到的最大价值,但背包问题还有很多种灵活的问法,在这里值得提一下。但是我认为,只要深入理解了求背包问题最大价值的方法,即使问法变化了,也是不难想出算法的。 例如,求解最多可以放多少件物品或者最多可以装满多少背包的空间。这都可以根据具体问题利用前面的方程求出所有状态的值(f数组)之后得到。 还有,如果要求的是“总价值最小”“总件数最小”,只需简单的将上面的状态转移方程中的max改成min即可。 下面说一些变化更大的问法。 输出方案 一般而言,背包问题是要求一个最优值,如果要求输出这个最优值的方案,可以参照一般动态规划问题输出方案的方法:记录下每个状态的最优值是由状态转移方程的哪一项推出来的,换句话说,记录下它是由哪一个策略推出来的。便可根据这条策略找到上一个状态,从上一个状态接着向前推即可。 还是以01背包为例,方程为f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}。再用一个数组g[i] [v],设g[i][v]=0表示推出f[i][v]的值时是采用了方程的前一项(也即f[i][v]=f[i-1][v]),g[i][v]表示采用了方程的后一项。注意这两项分别表示了两种策略:未选第i个物品及选了第i个物品。那么输出方案的伪代码可以这样写(设最终状态为f[N][V]): i=N v=V while(i>0) if(g[i][v]==0) print "未选第i项物品" else if(g[i][v]==1) print "选了第i项物品" v=v-c[i] 另外,采用方程的前一项或后一项也可以在输出方案的过程中根据f[i][v]的值实时地求出来,也即不须纪录g数组,将上述代码中的g[i] [v]==0改成f[i][v]==f[i-1][v],g[i][v]==1改成f[i][v]==f[i-1][v-c[i]]+w[i]也可。 输出字典序最小的最优方案 这里“字典序最小”的意思是1..N号物品的选择方案排列出来以后字典序最小。以输出01背包最小字典序的方案为例。 一般而言,求一个字典序最小的最优方案,只需要在转移时注意策略。首先,子问题的定义要略改一些。我们注意到,如果存在一个选了物品1的最优方案,那么答案一定包含物品1,原问题转化为一个背包容量为v-c[1],物品为2..N的子问题。反之,如果答案不包含物品1,则转化成背包容量仍为V,物品为2..N的子问题。不管答案怎样,子问题的物品都是以i..N而非前所述的1..i的形式来定义的,所以状态的定义和转移方程都需要改一下。但也许更简易的方法是先把物品逆序排列一下,以下按物品已被逆序排列来叙述。 在这种情况下,可以按照前面经典的状态转移方程来求值,只是输出方案的时候要注意:从N到1输入时,如果f[i][v]==f[i-v]及f[i][v]==f[i-1][f-c[i]]+w[i]同时成立,应该按照后者(即选择了物品i)来输出方案。 求方案总数 对于一个给定了背包容量、物品费用、物品间相互关系(分组、依赖等)的背包问题,除了再给定每个物品的价值后求可得到的最大价值外,还可以得到装满背包或将背包装至某一指定容量的方案总数。 对于这类改变问法的问题,一般只需将状态转移方程中的max改成sum即可。例如若每件物品均是01背包中的物品,转移方程即为f[i][v]=sum{f[i-1][v],f[i-1][v-c[i]]+w[i]},初始条件f[0][0]=1。 事实上,这样做可行的原因在于状态转移方程已经考察了所有可能的背包组成方案。 最优方案的总数 这里的最优方案是指物品总价值最大的方案。还是以01背包为例。 结合求最大总价值和方案总数两个问题的思路,最优方案的总数可以这样求:f[i][v]意义同前述,g[i][v]表示这个子问题的最优方案的总数,则在求f[i][v]的同时求g[i][v]的伪代码如下: for i=1..N for v=0..V f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]} g[i][v]=0 if(f[i][v]==f[i-1][v]) inc(g[i][v],g[i-1][v] if(f[i][v]==f[i-1][v-c[i]]+w[i]) inc(g[i][v],g[i-1][v-c[i]]) 如果你是第一次看到这样的问题,请仔细体会上面的伪代码。 小结 显然,这里不可能穷尽背包类动态规划问题所有的问法。甚至还存在一类将背包类动态规划问题与其它领域(例如数论、图论)结合起来的问题,在这篇论背包问题的专文中也不会论及。但只要深刻领会前述所有类别的背包问题的思路和状态转移方程,遇到其它的变形问法,只要题目难度还属于NOIP,应该也不难想出算法。不出去看看,又怎么会知道这个世界的魅力!]]></content>
<categories>
<category>ACM</category>
<category>背包九讲</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
<tag>背包问题</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day13]]></title>
<url>%2F2019%2F07%2F31%2FDay13%2F</url>
<content type="text"><![CDATA[Day13今天讲的是 背包 问题背包九讲(自闭快乐~~)今天先背包三讲01背包问题123456789101112131415161718192021222324题目:有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。基本思路这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}。这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。所以有必要将它详细解释一下:“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”;如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f [i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。注意f[i][v]有意义当且仅当存在一个前i件物品的子集,其费用总和为v。所以按照这个方程递推完毕后,最终的答案并不一定是f[N] [V],而是f[N][0..V]的最大值。如果将状态的定义中的“恰”字去掉,在转移方程中就要再加入一项f[i][v-1],这样就可以保证f[N] [V]就是最后的答案。至于为什么这样就可以,由你自己来体会了。优化空间复杂度以上方法的时间和空间复杂度均为O(N*V),其中时间复杂度基本已经不能再优化了,但空间复杂度却可以优化到O(V)。先考虑上面讲的基本思路如何实现,肯定是有一个主循环i=1..N,每次算出来二维数组f[i][0..V]的所有值。那么,如果只用一个数组f [0..V],能不能保证第i次循环结束后f[v]中表示的就是我们定义的状态f[i][v]呢?f[i][v]是由f[i-1][v]和f[i-1] [v-c[i]]两个子问题递推而来,能否保证在推f[i][v]时(也即在第i次主循环中推f[v]时)能够得到f[i-1][v]和f[i-1][v -c[i]]的值呢?事实上,这要求在每次主循环中我们以v=V..0的顺序推f[v],这样才能保证推f[v]时f[v-c[i]]保存的是状态f[i -1][v-c[i]]的值。伪代码如下:for i=1..Nfor v=V..0f[v]=max{f[v],f[v-c[i]]+w[i]};其中的f[v]=max{f[v],f[v-c[i]]}一句恰就相当于我们的转移方程f[i][v]=max{f[i-1][v],f[i- 1][v-c[i]]},因为现在的f[v-c[i]]就相当于原来的f[i-1][v-c[i]]。如果将v的循环顺序从上面的逆序改成顺序的话,那么则成了f[i][v]由f[i][v-c[i]]推知,与本题意不符,但它却是另一个重要的背包问题P02最简捷的解决方案,故学习只用一维数组解01背包问题是十分必要的。总结01背包问题是最基本的背包问题,它包含了背包问题中设计状态、方程的最基本思想,另外,别的类型的背包问题往往也可以转换成01背包问题求解。故一定要仔细体会上面基本思路的得出方法,状态转移方程的意义,以及最后怎样优化的空间复杂度。完全背包问题123456789101112131415161718192021222324题目有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。基本思路这个问题非常类似于01背包问题,所不同的是每种物品有无限件。也就是从每种物品的角度考虑,与它相关的策略已并非取或不取两种,而是有取0件、取1件、取2件……等很多种。如果仍然按照解01背包时的思路,令f[i][v]表示前i种物品恰放入一个容量为v的背包的最大权值。仍然可以按照每种物品不同的策略写出状态转移方程,像这样:f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k*c[i]<= v}。这跟01背包问题一样有O(N*V)个状态需要求解,但求解每个状态的时间则不是常数了,求解状态f[i][v]的时间是O(v/c[i]),总的复杂度是超过O(VN)的。将01背包问题的基本思路加以改进,得到了这样一个清晰的方法。这说明01背包问题的方程的确是很重要,可以推及其它类型的背包问题。但我们还是试图改进这个复杂度。一个简单有效的优化完全背包问题有一个很简单有效的优化,是这样的:若两件物品i、j满足c[i]<=c[j]且w[i]>=w[j],则将物品j去掉,不用考虑。这个优化的正确性显然:任何情况下都可将价值小费用高得j换成物美价廉的i,得到至少不会更差的方案。对于随机生成的数据,这个方法往往会大大减少物品的件数,从而加快速度。然而这个并不能改善最坏情况的复杂度,因为有可能特别设计的数据可以一件物品也去不掉。转化为01背包问题求解既然01背包问题是最基本的背包问题,那么我们可以考虑把完全背包问题转化为01背包问题来解。最简单的想法是,考虑到第i种物品最多选V/c [i]件,于是可以把第i种物品转化为V/c[i]件费用及价值均不变的物品,然后求解这个01背包问题。这样完全没有改进基本思路的时间复杂度,但这毕竟给了我们将完全背包问题转化为01背包问题的思路:将一种物品拆成多件物品。更高效的转化方法是:把第i种物品拆成费用为c[i]*2^k、价值为w[i]*2^k的若干件物品,其中k满足c[i]*2^k<V。这是二进制的思想,因为不管最优策略选几件第i种物品,总可以表示成若干个2^k件物品的和。这样把每种物品拆成O(log(V/c[i]))件物品,是一个很大的改进。但我们有更优的O(VN)的算法。 * O(VN)的算法这个算法使用一维数组,先看伪代码: <pre class"example"> for i=1..N for v=0..V f[v]=max{f[v],f[v-c[i]]+w[i]};你会发现,这个伪代码与P01的伪代码只有v的循环次序不同而已。为什么这样一改就可行呢?首先想想为什么P01中要按照v=V..0的逆序来循环。这是因为要保证第i次循环中的状态f[i][v]是由状态f[i-1][v-c[i]]递推而来。换句话说,这正是为了保证每件物品只选一次,保证在考虑“选入第i件物品”这件策略时,依据的是一个绝无已经选入第i件物品的子结果f[i-1][v-c[i]]。而现在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第i种物品”这种策略时,却正需要一个可能已选入第i种物品的子结果f[i][v-c[i]],所以就可以并且必须采用v= 0..V的顺序循环。这就是这个简单的程序为何成立的道理。这个算法也可以以另外的思路得出。例如,基本思路中的状态转移方程可以等价地变形成这种形式:f[i][v]=max{f[i-1][v],f[i][v-c[i]]+w[i]},将这个方程用一维数组实现,便得到了上面的伪代码。总结完全背包问题也是一个相当基础的背包问题,它有两个状态转移方程,分别在“基本思路”以及“O(VN)的算法“的小节中给出。希望你能够对这两个状态转移方程都仔细地体会,不仅记住,也要弄明白它们是怎么得出来的,最好能够自己想一种得到这些方程的方法。事实上,对每一道动态规划题目都思考其方程的意义以及如何得来,是加深对动态规划的理解、提高动态规划功力的好方法。多重背包问题12345678910111213141516171819202122题目有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。基本算法这题目和完全背包问题很类似。基本的方程只需将完全背包问题的方程略微一改即可,因为对于第i种物品有n[i]+1种策略:取0件,取1件……取 n[i]件。令f[i][v]表示前i种物品恰放入一个容量为v的背包的最大权值,则:f[i][v]=max{f[i-1][v-k*c[i]]+ k*w[i]|0<=k<=n[i]}。复杂度是O(V*∑n[i])。转化为01背包问题另一种好想好写的基本方法是转化为01背包求解:把第i种物品换成n[i]件01背包中的物品,则得到了物品数为∑n[i]的01背包问题,直接求解,复杂度仍然是O(V*∑n[i])。但是我们期望将它转化为01背包问题之后能够像完全背包一样降低复杂度。仍然考虑二进制的思想,我们考虑把第i种物品换成若干件物品,使得原问题中第i种物品可取的每种策略——取0..n[i]件——均能等价于取若干件代换以后的物品。另外,取超过n[i]件的策略必不能出现。方法是:将第i种物品分成若干件物品,其中每件物品有一个系数,这件物品的费用和价值均是原来的费用和价值乘以这个系数。使这些系数分别为 1,2,4,...,2^(k-1),n[i]-2^k+1,且k是满足n[i]-2^k+1>0的最大整数。例如,如果n[i]为13,就将这种物品分成系数分别为1,2,4,6的四件物品。分成的这几件物品的系数和为n[i],表明不可能取多于n[i]件的第i种物品。另外这种方法也能保证对于0..n[i]间的每一个整数,均可以用若干个系数的和表示,这个证明可以分0..2^k-1和2^k..n[i]两段来分别讨论得出,并不难,希望你自己思考尝试一下。这样就将第i种物品分成了O(log n[i])种物品,将原问题转化为了复杂度为O(V*∑log n[i])的01背包问题,是很大的改进。O(VN)的算法多重背包问题同样有O(VN)的算法。这个算法基于基本算法的状态转移方程,但应用单调队列的方法使每个状态的值可以以均摊O(1)的时间求解。由于用单调队列优化的DP已超出了NOIP的范围,故本文不再展开讲解。我最初了解到这个方法是在楼天成的“男人八题”幻灯片上。小结这里我们看到了将一个算法的复杂度由O(V*∑n[i])改进到O(V*∑log n[i])的过程,还知道了存在应用超出NOIP范围的知识的O(VN)算法。希望你特别注意“拆分物品”的思想和方法,自己证明一下它的正确性,并用尽量简洁的程序来实现。Bone CollectorDescription:涂奥最近迷上了吃鸡,房间有n个配件,每个配件有c(c<=1e3)的重量和v(v<=1e3)的价值,哇,涂奥捡了一个2级包,容量为s,所以涂奥最多当多肥的快递员呢?Input输入的第一行是T, 表示有一共要打T场比赛.每组数据由三行组成.第1行包含两个整数n和s 第2行包含n个整数, 表示每一个配件的价值. 第3行包含n个整数, 表示每个配件的重量.Output对每一组数据, 输出涂奥可以多肥.1234567Sample Input110 101 3 5 7 9 11 13 15 17 1919 17 15 13 11 9 7 5 3 1Sample Output51code:1234567891011121314151617181920212223242526272829303132333435#include<iostream>#include<cstring>#include<cstdio>#include<queue>#include<algorithm>#include<cmath>using namespace std;const int maxx = 1e3 + 10;const int mod = 1e7;int w[maxx], v[maxx];int dp[maxx][maxx];int main(){ int t, n, s; cin >> t; while(t --) { cin >> n >> s; for(int i = 1; i <= n; i ++) cin >> v[i]; for(int i = 1; i <= n; i ++) cin >> w[i]; for(int i = 1; i <= n; i ++) { for(int j = 0; j <= s; j ++) { if(j < w[i]) { dp[i][j] = dp[i - 1][j]; } else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]); } } cout << dp[n][s] << endl; } return 0;}饭卡Description:电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)。所以大家都希望尽量使卡上的余额最少。某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。Input多组数据。对于每组数据:第一行为正整数n,表示菜的数量。n<=1000。第二行包括n个正整数,表示每种菜的价格。价格不超过50。第三行包括一个正整数m,表示卡上的余额。m<=1000。n=0表示数据结束。Output对于每组输入,输出一行,包含一个整数,表示卡上可能的最小余额。1234567891011Sample Input1505101 2 3 2 1 1 2 3 2 1500Sample Output-4532code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950#include<iostream>#include<cstring>#include<cstdio>#include<queue>#include<algorithm>#include<cmath>using namespace std;const int maxx = 1e5;const int mod = 1e7;int w[maxx], v[maxx], num[maxx], dp[maxx];int main(){ int n, m; while(~scanf("%d",&n))//n表示菜的数量 { if(n == 0) break; int maxn = 0, max_id = -1, ans = 0, m; memset(dp, 0, sizeof dp); memset(w, 0, sizeof w); for(int i = 0; i < n; i ++) { cin >> w[i];//菜的价格 if(w[i] > maxn) { maxn = w[i];//记录最贵的菜价 max_id = i;//记录最贵菜的下标 } } w[max_id] = 0; cin >> m;//卡上余额 m -= 5;//预留5元最后买最贵的菜 int cnt = 0; for(int i = 0; i < n; i ++) { for(int j = m; j >= w[i]; j --) { if(dp[j] < dp[j - w[i]] + w[i]) dp[j] = dp[j - w[i]] + w[i]; if(dp[j] > cnt) cnt = dp[j]; } } if(m >= 0) ans = m - cnt - maxn + 5; else ans = m + 5; cout << ans << endl; } return 0;}CDDescription:You have a long drive by car ahead. You have a tape recorder, but unfortunately your best music is on CDs. You need to have it on tapes so the problem to solve is: you have a tape N minutes long. How to choose tracks from CD to get most out of tape space and have as short unused space as possible. Assumptions: • number of tracks on the CD does not exceed 20 • no track is longer than N minutes • tracks do not repeat • length of each track is expressed as an integer number • N is also integer Program should find the set of tracks which fills the tape best and print it in the same sequence as the tracks are stored on the CD Input Any number of lines.Each one contains value N, (after space) number of tracks and durations of the tracks. For example from first line in sample data: N = 5, number of tracks=3, first track lasts for 1 minute, second one 3 minutes, next one 4 minutes Output Set of tracks (and durations) which are the correct solutions and string ‘sum:’ and sum of duration times.123456789101112Sample Input5 3 1 3 410 4 9 8 4 220 4 10 5 7 490 8 10 23 1 2 3 4 5 745 8 4 10 44 43 12 9 8 2Sample Output1 4 sum:58 2 sum:1010 5 4 sum:1910 23 1 2 3 4 5 7 sum:554 10 12 9 8 2 sum:45code:123456789101112131415161718192021222324252627282930313233343536#include<bits/stdc++.h>using namespace std;int n,m,num;const int maxn=10005;int a[maxn],dp[maxn],flag[maxn][maxn];int main(){ ios::sync_with_stdio(0); cin.tie(0); while(cin>>n>>m) { for(int i=0;i<m;i++) cin>>a[i]; memset(flag,0,sizeof(flag)); memset(dp,0,sizeof(dp)); for(int i=m-1;i>=0;i--)//这里倒序主要是在输出的时候方便 { for(int j=n;j>=a[i];j--) { if(dp[j]<dp[j-a[i]]+a[i])//选上了a[i]的情况 { dp[j]=dp[j-a[i]]+a[i]; flag[i][j]=1;//进行标记 } } } for(int i=0,j=n;i<m;i++) { if(flag[i][j])//标价到的就输出 { cout<<a[i]<<" "; j-=a[i]; } } cout<<"sum:"<<dp[n]<<endl; }}Piggy-BankDescription:在 ACM 能够开展之前,必须准备预算,并获得必要的财力支持。该活动的主要收入来自于 Irreversibly Bound Money (IBM)。思路很简单。任何时候,某位 ACM 会员有少量的钱时,他将所有的硬币投入到小猪储钱罐中。这个过程不可逆,因为只有把小猪储钱罐打碎才能取出硬币。在足够长的时间之后,小猪储钱罐中有了足够的现金,用于支付 ACM 活动所需的花费。但是,小猪储钱罐存在一个大的问题,即无法确定其中有多少钱。因此,我们可能在打碎小猪储钱罐之后,发现里面的钱不够。显然,我们希望避免这种不愉快的情况。唯一的可能是,称一下小猪储钱罐的重量,并尝试猜测里面的有多少硬币。假定我们能够精确判断小猪储钱罐的重量,并且我们也知道给定币种的所有硬币的重量。那么,我们可以保证小猪储钱罐中最少有多少钱。你的任务是找出最差的情形,即判断小猪储钱罐中的硬币最少有多少钱。我们需要你的帮助。不能再贸然打碎小猪储钱罐了!小猪储钱罐了!输入输入包含 T 组测试数据。输入文件的第一行,给出了 T 的值。对于每组测试数据,第一行包含 E 和 F 两个整数,它们表示空的小猪储钱罐的重量,以及装有硬币的小猪储钱罐的重量。两个重量的计量单位都是 g (克)。小猪储钱罐的重量不会超过 10 kg (千克),即 1 <= E <= F <= 10000 。每组测试数据的第二行,有一个整数 N (1 <= N <= 500),提供了给定币种的不同硬币有多少种。接下来的 N 行,每行指定一种硬币类型,每行包含两个整数 P 和 W (1 <= P <= 50000,1 <= W <=10000)。P 是硬币的金额 (货币计量单位);W 是它的重量,以 g (克) 为计量单位。输出对于每组测试数据,打印一行输出。每行必须包含句子 “The minimum amount of money in the piggy-bank is X.” 其中,X 表示对于给定总重量的硬币,所能得到的最少金额。如果无法恰好得到给定的重量,则打印一行 “This is impossible.” 。123456789101112131415161718示例输入310 11021 130 5010 11021 150 301 6210 320 4示例输出The minimum amount of money in the piggy-bank is 60.The minimum amount of money in the piggy-bank is 100.This is impossible.code:1234567891011121314151617181920212223242526272829303132333435363738#include<iostream>#include<cstring>#include<cstdio>#include<queue>#include<algorithm>#include<cmath>using namespace std;const int maxx = 1e5;const int INF = 0x3f3f3f3f;const int mod = 1e7;int v[mod], w[mod];int dp[mod];int main(){ int T, n, m; int E, F; cin >> T; while(T --) { cin >> E >> F; cin >> n; for(int i = 1; i <= n; i ++) cin >> v[i] >> w[i]; for(int i = 1; i <= F - E; i ++) dp[i] = INF; for(int i = 1; i <= n; i ++) { for(int j = w[i]; j <= F - E; j ++) { dp[j] = min(dp[j], dp[j - w[i]] + v[i]); } } if(dp[F - E] != INF) printf("The minimum amount of money in the piggy-bank is %d.\n", dp[F - E]); else puts("This is impossible."); } return 0;}Dividing coinsDescription:It’s commonly known that the Dutch have invented copper-wire. Two Dutch men were fighting over a nickel, which was made of copper. They were both so eager to get it and the fighting was so fierce, they stretched the coin to great length and thus created copper-wire. Not commonly known is that the fighting started, after the two Dutch tried to divide a bag with coinsbetweenthetwoofthem. Thecontentsofthebagappearednottobeequallydivisible. TheDutch of the past couldn’t stand the fact that a division should favour one of them and they always wanted a fair share to the very last cent. Nowadays fighting over a single cent will not be seen anymore, but being capable of making an equal division as fair as possible is something that will remain important forever… That’s what this whole problem is about. Not everyone is capable of seeing instantly what’s the most fair division of a bag of coins between two persons. Your help is asked to solve this problem. Given a bag with a maximum of 100 coins, determine the most fair division between two persons. This means that the difference between the amount each person obtains should be minimised.The value of a coin varies from 1 cent to 500 cents. It’s not allowed to split a single coin. Input A line with the number of problems n, followed by n times: • a line with a non negative integer m (m ≤ 100) indicating the number of coins in the bag • a line with m numbers separated by one space, each number indicates the value of a coin. Output The output consists of n lines. Each line contains the minimal positive difference between the amount the two persons obtain when they divide the coins from the corresponding bag.123456789Sample Input 2 3 2 3 5 4 1 2 4 6 Sample Output 0 1code:12345678910111213141516171819202122232425#include<bits/stdc++.h>using namespace std;const int tx=1e5+10;int m[tx],dp[tx];int main(){ int n,t; cin>>n; while(n--) { cin>>t; memset(dp,0,sizeof(dp)); int sum=0; for(int i=0;i<t;i++) cin>>m[i],sum+=m[i]; for(int i=0;i<t;i++) { for(int j=sum/2;j>=m[i];j--) { dp[j]=max(dp[j],dp[j-m[i]]+m[i]); } } cout<<sum-dp[sum/2]-dp[sum/2]<<endl; } return 0;}RobberiesDescription:可怜的POIUYTREWQ最近想买下dota2的商品,但是手头缺钱。他想起了之前看过的一部大片,觉得抢银行也许是个不错的选择。他认为,坏人被抓是因为没有预先规划。于是他在之前的几个月对各大银行进行了一次评估; 评估内容包括安全性和可盗窃金额: 他想知道在在某个风险系数下可以偷窃的最大金额Input第一行给出了一个整数T, 表示有T组测试数据. 对于每一组数据,第一行给出了一个浮点数P, 表示POIUYTREWQ允许被抓的最大概率, 和一个整数N,表示他计划去抢劫的N个银行. 接下来N行, 每行给出一个整数数Mj和浮点数Pj.抢劫银行 j 可获得 Mj 百万美金, 被抓的概率是 Pj .Output对于每组数据,每行输出一个整数,表示POIUYTREWQ在被抓概率小于P的情况下,可抢到的最多的金钱。Notes and Constraints0 < T <= 1000.0 <= P <= 1.00 < N <= 1000 < Mj <= 1000.0 <= Pj <= 1.0你可以认为每家银行都是独立的。123456789101112131415161718Sample Input30.04 31 0.022 0.033 0.050.06 32 0.032 0.033 0.050.10 31 0.032 0.023 0.05Sample Output246code:123456789101112131415161718192021222324252627282930313233343536373839#include<bits/stdc++.h>using namespace std;const int maxn = 105;int m[maxn];double dp[100005],p[maxn];int main(){ ios::sync_with_stdio(0); int t; cin>>t; while(t--) { memset(dp,0,sizeof(dp)); double pp;int n,sum=0; cin>>pp>>n; for(int i=0;i<n;i++) { cin>>m[i]>>p[i]; sum+=m[i]; p[i]=1-p[i]; } dp[0]=1;//这个初始化很重要 for(int i=0;i<n;i++) { for(int j=sum;j>=m[i];j--) { dp[j]=max(dp[j],dp[j-m[i]]*p[i]); } } for(int i=sum;i>=0;i--) { if(dp[i]>=1-pp) { cout<<i<<endl; break; } } } return 0;}Coin ChangeDescription:Suppose there are 5 types of coins: 50-cent, 25-cent, 10-cent, 5-cent, and 1-cent. We want to make changes with these coins for a given amount of money. For example, if we have 11 cents, then we can make changes with one 10-cent coin and one 1-cent coin, two 5-cent coins and one 1-cent coin, one 5-cent coin and six 1-cent coins, or eleven 1-cent coins. So there are four ways of making changes for 11 cents with the above coins. Note that we count that there is one way of making change for zero cent. Write a program to find the total number of different ways of making changes for any amount of money in cents. Your program should be able to handle up to 7489 cents. Input The input file contains any number of lines, each one consisting of a number for the amount of money in cents. Output For each input line, output a line containing the number of different ways of making changes with the above 5 types of coins.123456Sample Input1126Sample Output413code:123456789101112131415161718192021222324252627282930#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>#include<cmath>using namespace std;typedef long long ll;const ll maxx = 10005;const int mod = 1e7;ll a[5] = {1, 5, 10, 25, 50};ll dp[maxx];int main(){ int n; while(cin >> n) { memset(dp, 0, sizeof dp); dp[0] = 1; for(ll i = 0; i < 5; i ++) { for(ll j = a[i]; j <= n; j ++) { dp[j] = dp[j] + dp[j - a[i]]; } } cout << dp[n] << endl; } return 0;}悼念512汶川大地震遇难同胞——珍惜现在,感恩生活Description:急!灾区的食物依然短缺!为了挽救灾区同胞的生命,心系灾区同胞的你准备自己采购一些粮食支援灾区,现在假设你一共有资金n元,而市场有m种大米,每种大米都是袋装产品,其价格不等,并且只能整袋购买。请问:你用有限的资金最多能采购多少公斤粮食呢?后记:人生是一个充满了变数的生命过程,天灾、人祸、病痛是我们生命历程中不可预知的威胁。月有阴晴圆缺,人有旦夕祸福,未来对于我们而言是一个未知数。那么,我们要做的就应该是珍惜现在,感恩生活——感谢父母,他们给予我们生命,抚养我们成人;感谢老师,他们授给我们知识,教我们做人感谢朋友,他们让我们感受到世界的温暖;感谢对手,他们令我们不断进取、努力。同样,我们也要感谢痛苦与艰辛带给我们的财富~Input输入数据首先包含一个正整数C,表示有C组测试用例,每组测试用例的第一行是两个整数n和m(1<=n<=100, 1<=m<=100),分别表示经费的金额和大米的种类,然后是m行数据,每行包含3个数p,h和c(1<=p<=20,1<=h<=200,1<=c<=20),分别表示每袋的价格、每袋的重量以及对应种类大米的袋数。Output对于每组测试数据,请输出能够购买大米的最多重量,你可以假设经费买不光所有的大米,并且经费你可以不用完。每个实例的输出占一行。1234567Sample Input18 22 100 44 100 2Sample Output400code:1234567891011121314151617181920212223242526272829303132333435363738394041#include<iostream>#include<cstring>#include<cstdio>#include<queue>#include<algorithm>#include<cmath>using namespace std;const int maxx = 110;const int mod = 1e7;int p[maxx];int h[maxx];int c[maxx];int dp[maxx];int main(){ int T, n, m; cin >> T; while(T --) { memset(dp, 0, sizeof dp); cin >> n >> m; for(int i = 1; i <= m; i ++) cin >> p[i] >> h[i] >> c[i]; for(int i = 1; i <= m; i ++) { for(int j = n; j >= 0; j --) { for(int k = 1; k <= c[i]; k ++) { if(j >= p[i] * k) dp[j] = max(dp[j], dp[j - p[i] * k] + h[i] * k); } } } cout << dp[n] << endl; } return 0;}/*外循环i大米种类,中间循环j经费,内循环k该大米数量,递推式即为:dp[j]=max(dp[j],dp[j-p[i]*k]+h[i]*k)。*/]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
<tag>背包问题</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day12]]></title>
<url>%2F2019%2F07%2F30%2FDay12%2F</url>
<content type="text"><![CDATA[Day12今天学习的是 记忆化搜索(还是和dp有关)OJ什么是记忆化搜索?搜索的低效在于没有能够很好地处理重叠子问题;动态规划虽然比较好地处理了重叠子问题,但是在有些拓扑关系比较复杂的题目面前,又显得无奈。记忆化搜索正是在这样的情况下产生的,它采用搜索的形式和动态规划中递推的思想将这两种方法有机地综合在一起,扬长避短,简单实用,在信息学中有着重要的作用。用一个公式简单地说:记忆化搜索=搜索的形式+动态规划的思想。动态规划的一种变形就是记忆化搜索,就是根据动归方程写出递归式,然后在函数的开头直接返回以前计算过的结果,当然这样做也需要一个存储结构记下前面计算过的结果,所以又称为记忆化搜索。记忆化搜索递归式动态规划记忆化搜索的思想记忆化搜索的思想是,在搜索过程中,会有很多重复计算,如果我们能记录一些状态的答案,就可以减少重复搜索量 记忆化搜索的适用范围根据记忆化搜索的思想,它是解决重复计算,而不是重复生成,也就是说,这些搜索必须是在搜索扩展路径的过程中分步计算的题目,也就是“搜索答案与路径相关”的题目,而不能是搜索一个路径之后才能进行计算的题目,必须要分步计算,并且搜索过程中,一个搜索结果必须可以建立在同类型问题的结果上,也就是类似于动态规划解决的那种。 也就是说,他的问题表达,不是单纯生成一个走步方案,而是生成一个走步方案的代价等,而且每走一步,在搜索树/图中生成一个新状态,都可以精确计算出到此为止的费用,也就是,可以分步计算,这样才可以套用已经得到的答案记忆化搜索的核心实现 a. 首先,要通过一个表记录已经存储下的搜索结果,一般用哈希表实现 b.状态表示,由于是要用哈希表实现,所以状态最好可以用数字表示,常用的方法是把一个状态连写成一个p进制数字,然后把这个数字对应的十进制数字作为状态 c.在每一状态搜索的开始,高效的使用哈希表搜索这个状态是否出现过,如果已经做过,直接调用答案,回溯 d.如果没有,则按正常方法搜索 记忆化搜索是类似于动态规划的,不同的是,它是倒做的“递归式动态规划”。Function Run FunDescription:We all love recursion! Don’t we?Consider a three-parameter recursive function w(a, b, c):if a <= 0 or b <= 0 or c <= 0, then w(a, b, c) returns: 1if a > 20 or b > 20 or c > 20, then w(a, b, c) returns: w(20, 20, 20)if a < b and b < c, then w(a, b, c) returns: w(a, b, c-1) + w(a, b-1, c-1) - w(a, b-1, c)otherwise it returns: w(a-1, b, c) + w(a-1, b-1, c) + w(a-1, b, c-1) - w(a-1, b-1, c-1)This is an easy function to implement. The problem is, if implemented directly, for moderate values of a, b and c (for example, a = 15, b = 15, c = 15), the program takes hours to run because of the massive recursion.InputThe input for your program will be a series of integer triples, one per line, until the end-of-file flag of -1 -1 -1. Using the above technique, you are to calculate w(a, b, c) efficiently and print the result.OutputPrint the value for w(a,b,c) for each triple.12345678910111213Sample Input1 1 12 2 210 4 650 50 50-1 7 18-1 -1 -1Sample Outputw(1, 1, 1) = 2w(2, 2, 2) = 4w(10, 4, 6) = 523w(50, 50, 50) = 1048576w(-1, 7, 18) = 1code:1234567891011121314151617181920212223242526272829//注意数组越界问题//#include<bits/stdc++.h>#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxx = 500;//int ans;//int dp[maxx];int mp[maxx][maxx][maxx];int w(int a, int b, int c){ if(a <= 0 || b <= 0 || c <= 0) return 1; if(mp[a][b][c]) return mp[a][b][c]; else if(a > 20 || b > 20 || c > 20) return mp[a][b][c] = w(20, 20, 20); else if(a < b && b < c) return mp[a][b][c] = w(a, b, c- 1) + w(a, b - 1, c - 1) - w(a, b - 1, c); else return mp[a][b][c] = w(a - 1, b, c) + w(a - 1, b - 1, c) + w(a - 1, b, c - 1) - w(a - 1, b - 1, c - 1);}int main(){ int a, b, c; while(~scanf("%d %d %d",&a, &b, &c)) { if(a == -1 && b == -1 && c== -1) break; printf("w(%d, %d, %d) = %d\n",a, b, c,w(a, b, c)); } return 0;}滑雪Description:Glory非常喜欢玩滑滑梯游戏,下面给出了一个n,m的滑道,其中的数字表示滑道的高度。Glory可以从一个点出发向下滑行,每次只能滑行到相邻的位置(上下左右)中高度严格低于当前高度的地方,不能重复划行已经滑行过的地方,但他希望在这个滑道上滑行尽量远的距离,也即是找一条最长的滑道。Input第一行输入两个数n,m代表滑梯范围行n和列m(1 <= n,m <= 100)。下面是n行,每行有m个整数,代表高度h,(0<=h<=20000)Output输出一个值,代表Glory能够在滑滑梯上面滑行的最长长度是多少1234567891011121314151617Sample Input3 39 1 25 6 78 4 3Sample Output4Sample Input4 77 6 5 4 3 2 11 5 1 1 1 1 11 4 3 1 1 1 11 5 6 7 8 1 1Sample Output7hint样例1:7->6->4->3 长度为4code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566//#include<bits/stdc++.h>#include<iostream>#include<cstring>#include<algorithm>#include<cstdio>using namespace std;const int maxx = 200;int mp[maxx][maxx];int dp[maxx][maxx];int n , m;int d[4][2] = { 0, 1, 0, -1, -1, 0, 1, 0};int dfs(int x, int y){ //如果已经找过,退出此次搜索 if(dp[x][y]) return dp[x][y]; int maxlen = 1; int len; for(int i = 0; i < 4; i ++) { int xx = x + d[i][0]; int yy = y + d[i][1]; if(xx >= 0 && yy >= 0 && xx < n && yy < m && mp[xx][yy] > mp[x][y]) { //能够遍历一次,步数+1 len = dfs(xx, yy) + 1; //不断比较,找该点所能够到达的最大长度 maxlen = max(maxlen, len); } } return dp[x][y] = maxlen;}int main(){ int ans; while(~scanf("%d %d",&n, &m)) { ans = 0; memset(mp, 0, sizeof mp); memset(dp, 0, sizeof dp); for(int i = 0; i < n; i ++) { for(int j = 0; j < m; j ++) cin >> mp[i][j]; } for(int i = 0; i < n; i ++) { for(int j = 0; j < m; j ++) { //便利搜索每一个点所能到达的最大距离并保存 dp[i][j] = dfs(i, j); //不断比较找出最大值 ans = max(ans, dp[i][j]); } } cout << ans << endl; }// cin >> n >> m; return 0;}漫步校园Description:LL最近沉迷于AC不能自拔,每天寝室、机房两点一线。由于长时间坐在电脑边,缺乏运动。他决定充分利用每次从寝室到机房的时间,在校园里散散步。整个HDU校园呈方形布局,可划分为n*n个小方格,代表各个区域。例如LL居住的18号宿舍位于校园的西北角,即方格(1,1)代表的地方,而机房所在的第三实验楼处于东南端的(n,n)。因有多条路线可以选择,LL希望每次的散步路线都不一样。另外,他考虑从A区域到B区域仅当存在一条从B到机房的路线比任何一条从A到机房的路线更近(否则可能永远都到不了机房了…)。现在他想知道的是,所有满足要求的路线一共有多少条。你能告诉他吗?Input每组测试数据的第一行为n(2=<n<=50),接下来的n行每行有n个数,代表经过每个区域所花的时间t(0<t<=50)(由于寝室与机房均在三楼,故起点与终点也得费时)。Output针对每组测试数据,输出总的路线数(小于2^63)。123456789101112Sample Input31 2 31 2 31 2 331 1 11 1 11 1 1Sample Output16code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182//#include <bits/stdc++.h>#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>#include<queue>using namespace std;typedef long long ll;int n;struct node{ int x,y,c; bool friend operator < (node a,node b){ return a.c > b.c; }}r,w;ll ma[330][330];int vis[330][330];ll dis[330][330];ll dp[330][330]; //记忆数组 要用long long int Next[4][2] = {0,1,0,-1,1,0,-1,0};void bfs(){ //bfs求终点到其余各点的最短路 priority_queue<node> q; r.x = r.y = n-1;r.c = ma[n-1][n-1]; //以终点作为起点 dis[n-1][n-1] = ma[n-1][n-1];; vis[n-1][n-1] = 1; q.push(r); while(!q.empty()) { r = q.top(); q.pop(); for(int i = 0; i < 4; i++) { int nx = r.x + Next[i][0]; int ny = r.y + Next[i][1]; if(nx < 0 || ny < 0 || nx >= n || ny >= n || vis[nx][ny]) continue; w.x = nx; w.y = ny; w.c = r.c + ma[nx][ny]; vis[nx][ny] = 1; q.push(w); dis[nx][ny] = w.c; } }}ll dfs(int x,int y){ //dfs求最短路径条数 if(x == n-1 && y == n-1) { return 1; } if(dp[x][y] != -1) return dp[x][y]; dp[x][y] = 0; for(int i = 0; i < 4; i++) { int nx = x + Next[i][0]; int ny = y + Next[i][1]; if( nx < 0 || ny < 0 || nx >= n || ny >= n || dis[nx][ny] >= dis[x][y]) continue; dp[x][y] += dfs(nx,ny); } return dp[x][y];}int main(){ while(cin >> n) { for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) cin >> ma[i][j]; } memset(vis,0,sizeof vis); memset(dp,-1,sizeof dp); bfs(); cout << dfs(0,0) << '\n'; } return 0;}Free CandiesDescription:Little Bob is playing a game. He wants to win some candies in it - as many as possible. There are 4 piles, each pile contains N candies. Bob is given a basket which can hold at most 5 candies. Each time, he puts a candy at the top of one pile into the basket, and if there’re two candies of the same color in it, he can take both of them outside the basket and put them into his own pocket. When the basket is full and there are no two candies of the same color, the game ends. If the game is played perfectly, the game will end with no candies left in the piles. For example, Bob may play this game like this (N = 5):Note that different numbers indicate different colors, there are 20 kinds of colors numbered 1..20. ‘Seems so hard…’ Bob got very much puzzled. How many pairs of candies could he take home at most?InputThe input will contain not more than 10 test cases. Each test case begins with a line containing a single integer n(1 ≤ n ≤ 40) representing the height of the piles. In the following n lines, each line contains four integers xi1, xi2, xi3, xi4 (in the range 1..20). Each integer indicates the color of the corresponding candy. The test case containing n = 0 will terminate the input, you should not give an answer to this case.OutputOutput the number of pairs of candies that the cleverest little child can take home. Print your answer in a single line for each test case.1234Sample Input5 1 2 3 4 1 5 6 7 2 3 3 3 4 9 8 6 8 7 2 1 1 1 2 3 4 3 1 2 3 4 5 6 7 8 1 2 3 4 0Sample Output8 0 3code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859//#include <bits/stdc++.h>#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>using namespace std;typedef long long ll;int n;int dp[55][55][55][55]; //记忆数组bool Basket[555]; //标记篮子内的糖果int ma[5][55]; //存糖果int top[5]; //记录取到第几个糖果 例如 top[0] = 1 表示已经取到了第0堆的第一个糖果int dfs(int x){ if(dp[top[0]][top[1]][top[2]][top[3]] != -1) return dp[top[0]][top[1]][top[2]][top[3]]; //判断是否搜索 if(x == 5) return 0; //如果篮子内糖果数为5 游戏结束 int ans = 0; for(int i = 0; i < 4; i++) { if(top[i] == n) continue; //top[i] == n 表示第i堆取完,continue即取下一堆 int now = ma[i][top[i]]; //now 表示即将要放入篮子的糖果 top[i]++; //top[i]++为下次取糖果准备,即下一次取第i堆的下一个糖果 if(Basket[now]) { //如果篮子中存在与即将要放入篮子的糖果相同的糖果 Basket[now] = 0; //从篮子中拿出糖果 ans = max(ans,dfs(x-1) + 1); //更新结果 Basket[now] = 1; //回溯 } else { Basket[now] = 1; //如果篮子中不存在这个糖果,将糖果放入篮子 ans = max(ans,dfs(x+1)) ; //更新结果 Basket[now] = 0; //回溯 } top[i]--; //回溯 } return dp[top[0]][top[1]][top[2]][top[3]] = ans; //记忆}int main(){ while(cin >> n && n) { for(int i = 0; i < n; i++) { for(int j = 0; j < 4; j++) cin >> ma[j][i]; } memset(dp,-1,sizeof dp); memset(Basket,0,sizeof Basket); memset(top,0,sizeof top); cout << dfs(0) << '\n'; } return 0;}ZipperDescription:Given three strings, you are to determine whether the third string can be formed by combining the characters in the first two strings. The first two strings can be mixed arbitrarily, but each must stay in its original order.For example, consider forming “tcraete” from “cat” and “tree”:String A: catString B: treeString C: tcraeteAs you can see, we can form the third string by alternating characters from the two strings. As a second example, consider forming “catrtee” from “cat” and “tree”:String A: catString B: treeString C: catrteeFinally, notice that it is impossible to form “cttaree” from “cat” and “tree”.InputThe first line of input contains a single positive integer from 1 through 1000. It represents the number of data sets to follow. The processing for each data set is identical. The data sets appear on the following lines, one data set per line.For each data set, the line of input consists of three strings, separated by a single space. All strings are composed of upper and lower case letters only. The length of the third string is always the sum of the lengths of the first two strings. The first two strings will have lengths between 1 and 200 characters, inclusive.OutputFor each data set, print:Data set n: yesif the third string can be formed from the first two, orData set n: noif it cannot. Of course n should be replaced by the data set number. See the sample output below for an example.123456789Sample Input3cat tree tcraetecat tree catrteecat tree cttareeSample OutputData set 1: yesData set 2: yesData set 3: nocode:123456789101112131415161718192021222324252627282930313233343536373839404142434445//#include<bits/stdc++.h>#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>using namespace std;const int maxx = 1e3;string str1, str2, str;bool pos;bool vis[maxx][maxx];void dfs(int x, int y, int z){ //如果长度相同的话就回溯,表示结束 if(x == str1.length() && y == str2.length()) { //能够都遍历表示可以 pos = 1; return; } if(str1[x] != str[z] && str2[y] != str[z]) return; if(vis[x][y]) return; vis[x][y] = 1; if(str1[x] == str[z]) dfs(x + 1, y, z + 1); if(str2[y] == str[z]) dfs(x, y + 1, z + 1);}int main(){ int n, k = 1; cin >> n; while(n --) { memset(vis, 0, sizeof vis); cin >> str1 >> str2 >> str; pos = 0; dfs(0, 0, 0); if(pos) printf("Data set %d: yes\n",k ++); else printf("Data set %d: no\n", k ++); } return 0;}Bone CollectorDescription:Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave …The bone collector had a big bag with a volume of V ,and along his trip of collecting there are a lot of bones , obviously , different bone has different value and different volume, now given the each bone’s value along his trip , can you calculate out the maximum of the total value the bone collector can get ?InputThe first line contain a integer T , the number of cases.Followed by T cases , each case three lines , the first line contain two integer N , V, (N <= 1000 , V <= 1000 )representing the number of bones and the volume of his bag. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.OutputOne integer per line representing the maximum of the total value (this number will be less than 2 31).1234567Sample Input15 101 2 3 4 55 4 3 2 1Sample Output14code:123456789101112131415161718192021222324252627282930313233343536373839#include<bits/stdc++.h>using namespace std;const int maxx = 1e3 + 10;int w[maxx];int v[maxx];int s[maxx][maxx];int main(){ int t, n, m; cin >> t; while(t --) { memset(s, 0, sizeof s); cin >> n >> m; for(int i = 1; i <= n; i ++) cin >> v[i]; //骨骼价值 for(int i = 1; i <= n; i ++) cin >> w[i]; //骨骼体积 //i表示第i个骨骼,j表示背包容量 for(int i = 1; i <= n; i ++) { for(int j = 0; j <= m; j ++) { //是否选择第i个就要看容量是否大于它的重量 if(j >= w[i]) { //拿,那么就必须要占用当前背包的空间。即用当前背包总容量 j-w[i],再占用1个物品空间,所以i-1,此时的总价值就是m [i-1][j-w[i]] 的解+当前的价值v[i] ,得到的就是放入当前物品得到的最优解。 s[i][j] = max(s[i - 1][j], s[i - 1][j-w[i]] + v[i]); } else //不拿,那么就还是上一步的解,m[i-1][j] s[i][j] = s[i - 1][j]; } } cout << s[n][m] << endl; } return 0;}FatMouse and CheeseDescription:有一种游戏是的玩法是这样的:有一个n*n的格子,每个格子有一个数字。遵循以下规则:玩家每次可以由所在格子向上下左右四个方向进行直线移动,每次移动的距离不得超过m玩家一开始在第一行第一列,并且已经获得该格子的分值玩家获得每一次移动到的格子的分值玩家下一次移动到达的格子的分值要比当前玩家所在的格子的分值要大。游戏所有数字加起来也不大,保证所有数字的和不会超过int型整数的范围玩家仅能在n*n的格子内移动,超出格子边界属于非法操作当玩家不能再次移动时,游戏结束现在问你,玩家所能获得的最大得分是多少?Input有多组测试数据每组测试样例第一行是两个整数n,m (1≤n≤100)(1≤m≤100),当n和m都是-1时为程序结束标志,直接退出即可之后n行,每行n个数字,描述n*n的格子里的数字Output对于每组测试数据输出一行,这一行仅有一个整数,代表玩家所能获得的最高得分12345678Sample Input3 11 2 510 11 612 12 7-1 -1Sample Output37code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061#include<bits/stdc++.h>using namespace std;const int maxx = 200;int a[maxx][maxx];int dp[maxx][maxx];int m, n;int d[4][2] = { 0, 1, 0, -1, 1, 0, -1, 0};int dfs(int x, int y){ if(dp[x][y]) return dp[x][y]; int maxsorce = 0; int sorce; for(int i = 0; i < 4; i ++) { for(int j = 1; j <= m; j ++) { int xx = x + (d[i][0]) * j; int yy = y + (d[i][1]) * j; if(xx >= 0 && y >= 0 && x < n && y < n && a[xx][yy] > a[x][y]) { sorce = dfs(xx, yy); maxsorce = max(sorce, maxsorce); } } } dp[x][y] = maxsorce + a[x][y];//回溯到x,y的最大和(顺序从大到小) return dp[x][y];}int main(){ while(~scanf("%d %d",&n, &m)) { memset(a, 0, sizeof a); memset(dp, 0, sizeof dp); if(n == -1 && m == -1) break; for(int i = 0; i < n ; i ++) { for(int j = 0; j < n; j ++) { cin >> a[i][j]; } } dfs(0, 0); cout << dp[0][0] << endl; } return 0;}/*1.关于移动问题:由于题中移动范围并不是1可以扩大到1*k所以仍然需要构造移动方向,只是需要dfs四周范围为k。2.可以从最后一个节点往回遍历,也就是需要先找到最大的值,然后往回找,如何实现呢,用递归。但是需要标记路径不然会爆的。*/送披萨Description:何老板开了一家披萨店,有一天突然收到了n个客户的订单。何老板所在的城市只有一条笔直的大街,我们可以将它想象成数轴,其中位置0是何老板的披萨店,第i个客户所在的位置为Pi,每个客户的位置都不同。如果何老板给第i个客户送披萨,客户会支付Ei-Ti块钱,其中Ti是何老板到达他家的时刻。当然,如果到得太晚,会使得Ei-Ti<0,这时,何老板可以选择不给他送餐,免得他反过来找何老板要钱。何老板店里面只有一个送餐车(单位时间行驶单位长度的距离),因此只能往返送餐,如下图所示就是一条线路,图中第一行的数字是位置Pi,第二行是Ei。你的任务是帮助何老板计算出最大的收益。Input第一行,一个整数n第二行,n个空格间隔的整数,从左往右给出了每个客户的位置Pi,即P1,P2,……,Pn第三行,n个空格间隔的整数,从左往右给出了每个客户对应的Ei,即E1,E2,……,EnOutput一行,一个整数,表示所求的最佳收益。1234567891011121314151617181920212223Sample Input5-6 -3 -1 2 5 27 10 2 5 20Sample Output32Sample Input6 1 2 4 7 11 14 3 6 2 5 18 10Sample Output13Sample Input11-14 -13 -12 -11 -10 1 2 3 4 5 100 200 200 200 200 200 200 200 200 200 200 200Sample Output1937数据范围1 ≤ n ≤ 100-100,000 ≤ Pi ≤ 100,000 且Pi!=0 0< Ei ≤ 100,000code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859#include<cstdio>#include<iostream>#include<algorithm>#include<cstdlib>#include<cstring>using namespace std;int f[205][205][205][2];bool mark[205][205][205][2];int n;int pos[205],e[205],start;int dp(int l,int r,int cnt,int p){ int i; if(mark[l][r][cnt][p])return f[l][r][cnt][p]; mark[l][r][cnt][p]=true; if(cnt==0)return f[l][r][cnt][p]=0; if(p==0){ for(i=1;i<l;i++){ f[l][r][cnt][p]=max(f[l][r][cnt][p],dp(i,r,cnt-1,0)+e[i]-cnt*abs(pos[l]-pos[i])); } for(i=r+1;i<=n+1;i++){ f[l][r][cnt][p]=max(f[l][r][cnt][p],dp(l,i,cnt-1,1)+e[i]-cnt*abs(pos[l]-pos[i])); } } else{ for(i=1;i<l;i++){ f[l][r][cnt][p]=max(f[l][r][cnt][p],dp(i,r,cnt-1,0)+e[i]-cnt*abs(pos[r]-pos[i])); } for(i=r+1;i<=n+1;i++){ f[l][r][cnt][p]=max(f[l][r][cnt][p],dp(l,i,cnt-1,1)+e[i]-cnt*abs(pos[r]-pos[i])); } } return f[l][r][cnt][p];}int main(){ int i,j,ans=0; start=0; cin>>n; for(i=1;i<=n+1;i++){ cin>>pos[i]; if(pos[i]>0&&start==0){ start=i; pos[i+1]=pos[i]; pos[i]=0; i++; } } for(i=1;i<=n+1;i++){ cin>>e[i]; if(start==i){ e[i+1]=e[i]; e[i]=0; i++; } } for(i=0;i<=n;i++){ ans=max(ans,dp(start,start,i,0)); } cout<<ans;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
<tag>动态规划</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day11]]></title>
<url>%2F2019%2F07%2F29%2FDay11%2F</url>
<content type="text"><![CDATA[Day11今天学习的是 动态规划(dp) + 最大字段和问题 + 最长公共子序列 + 编辑距离 + 最长递增子序列重点还是动态规划(dp)动态规划简介:动态规划:就是一个最优化问题,先将问题分解为子问题,并且对于这些分解的子问题自身就是最优的才能在这个基础上得出我们要解决的问题的最优方案,要不然的话就能找到一个更优的解来替代这个解,得出新的最优自问题,这当然是和前提是矛盾的。动态规划不同于 贪心算法,因为贪心算法是从局部最优来解决问题,而动态规划是全局最优的。用动态规划的时候不可能在子问题还没有得到最优解的情况下就做出决策,而是必须等待子问题得到了最优解之后才对当下的情况做出决策,所以往往动态规划都可以用 一个或多个递归式来描述。而贪心算法却是先做出一个决策,然后在去解决子问题。这就是贪心和动态规划的不同。一般遇到一个动态规划类型的问题,都先要确定最优子结构,还有重叠子问题,这两个是动态规划最大的特征,然后就是要写 动态规划的状态方程,这个步骤十分十分的重要的,写动归方程是需要一定的经验的,这可以通过训练来达到目的。接着就是要自底向上的求解问题的,先将最小规模的子问题的最优解求出,一般都用一张表来记录下求得的解,到后来遇到同样的子问题的时候就可以直接查表得到答案,最后就是通过一步一步的迭代得出最后问题的答案了。我的理解最重要的东西就是一定会要一个数组或者其他的存储结构存储得到的子问题的解。这样就可以省很多时间,也就是典型的空间换时间The King’s Ups and DownsDescription:The king has guards of all different heights. Rather than line them up in increasing or decreasing height order, he wants to line them up so each guard is either shorter than the guards next to him or taller than the guards next to him (so the heights go up and down along the line). For example, seven guards of heights 160, 162, 164, 166, 168, 170 and 172 cm. could be arranged as:or perhaps:he king wants to know how many guards he needs so he can have a different up and down order at each changing of the guard for rest of his reign. To be able to do this, he needs to know for a given number of guards, n, how many different up and down orders there are:For example, if there are four guards: 1, 2, 3,4 can be arrange as:1324, 2143, 3142, 2314, 3412, 4231, 4132, 2413, 3241, 1423For this problem, you will write a program that takes as input a positive integer n, the number of guards and returns the number of up and down orders for n guards of differing heights.InputThe first line of input contains a single integer P, (1 <= P <= 1000), which is the number of data sets that follow. Each data set consists of single line of input containing two integers. The first integer, D is the data set number. The second integer, n (1 <= n <= 20), is the number of guards of differing heights.OutputFor each data set there is one line of output. It contains the data set number (D) followed by a single space, followed by the number of up and down orders for the n guards.1234567891011Sample Input41 12 33 44 20Sample Output1 12 43 104 740742376475050code:1234567891011121314151617181920212223242526272829#include<bits/stdc++.h>using namespace std;const int maxn=25;typedef long long ll;ll dp[maxn][maxn],ans[maxn];void init(){ dp[1][1]=1;ans[1]=1; for(int i=2;i<=20;i++) { for(int k=2;k<=i;k++) { dp[i][k]=dp[i-1][i+1-k]+dp[i][k-1]; ans[i]+=dp[i][k]; } ans[i]*=2; }}int main(){ init(); int p,m,n; cin>>p; while(p--) { cin>>m>>n; cout<<m<<" "<<ans[n]<<endl; }}数塔Description:在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的:有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?已经告诉你了,这是个DP的题目,你能AC吗?Input输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数,且所有的整数均在区间[0,99]内。Output对于每个测试实例,输出可能得到的最大和,每个实例的输出占一行。12345678910Sample Input1573 88 1 02 7 4 44 5 2 6 5Sample Output30code:123456789101112131415161718192021222324252627282930#include<bits/stdc++.h>using namespace std;const int maxx = 1000;int a[maxx][maxx];int main(){ int t, n; cin >> t; while(t --) { cin >> n; for(int i = 0; i < n; i ++) { for(int j = 0; j < i + 1; j ++) { cin >> a[i][j]; } } for(int i = n - 2; i >= 0; i --) { for(int j = 0; j <= i; j ++) { a[i][j] = max(a[i + 1][j], a[i + 1][j + 1]) + a[i][j]; } } cout << a[0][0] << endl; } return 0;}母牛的故事Description:有一头母牛,它每年年初生一头小母牛。每头小母牛从第四个年头开始,每年年初也生一头小母牛。请编程实现在第n年的时候,共有多少头母牛?Input输入数据由多个测试实例组成,每个测试实例占一行,包括一个整数n(0<n<55),n的含义如题目中描述。n=0表示输入数据的结束,不做处理。Output对于每个测试实例,输出在第n年的时候母牛的数量。每个输出占一行。123456789Sample Input2450Sample Output246code:123456789101112131415161718#include<bits/stdc++.h>using namespace std;const int maxx = 1e7;int a[maxx];int main(){ int n; a[1] = 1, a[2] = 2, a[3] = 3, a[4] = 4; for(int i = 5; i < 55; i ++) a[i] = a[i - 1] + a[i - 3]; while(~scanf("%d",&n)) { if(n == 0) break; cout << a[n] << endl; } return 0;}一只小蜜蜂…Description:有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行。请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数。其中,蜂房的结构如下所示。Input输入数据的第一行是一个整数N,表示测试实例的个数,然后是N 行数据,每行包含两个整数a和b(0<a<b<50)。Output对于每个测试实例,请输出蜜蜂从蜂房a爬到蜂房b的可能路线数,每个实例的输出占一行。1234567Sample Input21 23 6Sample Output13code:12345678910111213141516171819202122#include<bits/stdc++.h>using namespace std;const int maxx = 1e6;long long a[maxx];int main(){ int n, x, y; cin >> n; a[0] = 1, a[1] = 1, a[2] = 2; for(int i = 3; i < 60; i ++) { a[i] = a[i - 1] + a[i - 2]; } while(n --) { cin >> x >> y; cout << a[y - x] << endl; } return 0;}超级楼梯Description:有一楼梯共M级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第M级,共有多少种走法?Input输入数据首先包含一个整数N,表示测试实例的个数,然后是N行数据,每行包含一个整数M(1<=M<=40),表示楼梯的级数。Output对于每个测试实例,请输出不同走法的数量1234567Sample Input223Sample Output12code:12345678910111213141516171819202122#include<bits/stdc++.h>using namespace std;const int maxx = 1e6;int a[maxx];int main(){ int t, n; cin >> t; a[0] = 0; a[1] = 1; a[2] = 2; for(int i = 3; i <= 40; i ++) { a[i] = a[i - 1] + a[i - 2]; } while(t --) { cin >> n; cout << a[n - 1] << endl; } return 0;}TicketsDescription:现在有n个人要买电影票,如果知道每个人单独买票花费的时间,还有和前一个人一起买花费的时间,问最少花多长时间可以全部买完票。Input给出 N(1<=N<=10),表示有N组样例 给出K (1<=K<=2000),表示有K个人买票.. 给出K个数表示这个人单独买票会花的时间..保证每个数 (0s<=Si<=25s) 给出K-1个数,表示这个人和前面那个人一起买票会花的时间..保证每个数 (0s<=Si<=50s)Output对于每一组数据,你需要给出电影院售票结束的时间,售票开始的时间为 08:00:00 am. 时间格式为: HH:MM:SS am|pm. 具体看样例输出12345678910Sample Input2220 254018Sample Output08:00:40 am08:00:08 amcode:1234567891011121314151617181920212223242526272829#include<bits/stdc++.h>using namespace std;const int maxn=2005;int s[maxn],d[maxn],ans[maxn];int main(){ int n,k; cin>>n; while(n--) { cin>>k; for(int i=1;i<=k;i++) cin>>s[i]; for(int j=2;j<=k;j++) cin>>d[j]; ans[1]=s[1]; for(int i=2;i<=k;i++) { ans[i]=min(ans[i-1]+s[i],ans[i-2]+d[i]); } int time=ans[k];int h,m,s; h=time/3600; m=time%3600/60; s=time%3600%60; h+=8; if(h<=12) printf("%02d:%02d:%02d am\n",h,m,s); else printf("%02d:%02d:%02d pm\n",h-12,m,s); }}钱币兑换问题Description:在一个国家仅有1分,2分,3分硬币,将钱N兑换成硬币有很多种兑法。请你编程序计算出共有多少种兑法。Input每行只有一个正整数N,N小于32768。Output对应每个输入,输出兑换方法数。123456Sample Input293412553Sample Output71883113137761code:123456789101112131415161718192021222324#include<bits/stdc++.h>using namespace std;typedef long long ll;int a[33005];int main(){ int n; memset(a, 0, sizeof a); a[0] = 1; for(int i = 1; i <= 3; i ++) { for(int j = i; j <= 33000; j ++) { a[j] = max(a[j], a[j] + a[j - i]); } } while(~scanf("%d",&n)) { cout << a[n] << endl; } return 0;}Ignatius and the Princess IVDescription:给你n个数字,请你找出出现至少(n+1)/2次的数字。输入本题包含多组数据,请处理到EOF:每组数据包含两行。第一行一个数字N(1<=N<=999999) ,保证N为奇数。第二行为N个用空格隔开的整数。输出对于每组数据,输出一行,表示要求找到的那个数1234567891011样例输入51 3 2 3 3111 1 1 1 1 5 5 5 5 5 571 1 1 1 1 1 1样例输出351code:12345678910111213141516171819202122#include<bits/stdc++.h>using namespace std;int a[1000000];int main(){ int n, t, ans; while(~scanf("%d",&n)) { memset(a, 0, sizeof a); ans = 0; //遍历查找,如果数字相同,加一 for(int i = 0; i < n; i ++) { cin >> t; a[t] ++; if(a[t] >= (n + 1) / 2) ans = t; } cout << ans << endl; } return 0;}最少拦截系统Description:某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的高度.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹.怎么办呢?多搞几套系统呗!你说说倒蛮容易,成本呢?成本是个大问题啊.所以俺就到这里来求救了,请帮助计算一下最少需要多少套拦截系统.Input输入若干组数据.每组数据包括:导弹总个数(正整数),导弹依此飞来的高度(雷达给出的高度数据是不大于30000的正整数,用空格分隔)Output对应每组数据输出拦截所有导弹最少要配备多少套这种导弹拦截系统.1234Sample Input8 389 207 155 300 299 170 158 65Sample Output2code:123456789101112131415161718192021222324252627282930313233#include <bits/stdc++.h>using namespace std;const int MAXX=100000+5;const int INF=INT_MAX;int a[MAXX],dp[MAXX];// a数组为数据,dp[i]表示以a[i]结尾的最长递增子序列长度int main(){ int n; while(cin>>n) { for(int i=0; i<n; i++) { cin>>a[i]; dp[i]=1; // 初始化为1,长度最短为自身 } int ans=1; for(int i=1; i<n; i++)//枚举子序列的终点 { for(int j=0; j<i; j++)//从头向终点检查每一个元素 { if(a[i]>a[j]) { dp[i]=max(dp[i],dp[j]+1); // 状态转移 } } ans=max(ans,dp[i]); // 比较每一个dp[i],最大值为答案 } cout<<ans<<endl; } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
<tag>图论</tag>
<tag>动态规划</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day10]]></title>
<url>%2F2019%2F07%2F27%2FDay10%2F</url>
<content type="text"><![CDATA[Day10今天是 又一次 积分赛我心态很好,真的很好,,,,真的很好。。。。OJ再战斐波那契Problem DescriptionDescription:小z 学会了斐波那契和 gcd 后,老师又给他出了个难题,求第N个和第M个斐波那契数的最大公约数,这可难倒了小z ,不过在小z 的再三请求下,老师又告诉他了个条件,gcd(N,M)∈[1,90]。可是,笨拙的小z 还是不会,于是请求你帮他解答这个问题。已知:输入格式输入包括 T 组,T∈[1,10].接下来 T 行,每行两个整数 N,M, 表示斐波那契的第 N 项和第 M 项,(N,M∈[1,1e18]).输出格式输出包含 T 行,每行输出一个整数.样例input31 22 33 4output111code:1234567891011121314151617181920//gcd(f(m),f(n)) = f(gcd(m,n))这个是规律#include<bits/stdc++.h>using namespace std;typedef long long ll;ll a[1000];int main(){ int n; scanf("%d",&n); ll x, y; a[2] = 1, a[1] = 1; for(int i = 3; i <= 100; i ++) a[i] = a[i - 1] + a[i - 2]; for(int i = 0; i < n; i ++) { scanf("%lld %lld",&x, &y); printf("%lld\n",a[__gcd(x, y)]); } return 0;}恐怖的怪物Description:一天早上,Dicer一觉醒来,发现自己来到了MineCraft的世界里面,身为MineCraft游戏爱好者的他欣喜不已,于是他在地下挖了一片长方体的空间作为秘密基地,可是他发现光照亮度小于等于7时,会有恐怖的怪物出现,并且他通过查阅资料发现光源方块产生光照每一米(方格)衰减1光照等级。此规律在坐标轴的3个方向上(东西、南北、上下)均成立。换句话来说,对角线方向的光照衰减依照“曼哈顿距离”(两个点在坐标系上的绝对轴距总和)计算。这意味着,假如地上插着一支火把(光照等级14),则在水平面上与火把相邻的4个方向的方格上光照等级均为13,而在水平面上与火把对角的4个方格上光照等级均为12(譬如,西北方格的光照等级为14-向西1级-向北1级)。上述这种衰减特性会在光源周围产生菱形的照明。该效果会在光源周围的光源扩散呈钻石状。如果被不透明方块阻挡,光照也可以沿着复杂而弯曲的路径扩散。如下图所示,红色为光源(亮度等级为14),黑色为秘密物品,其余各个位置光照强度如图所示。秘密基地为N∗M的空间,不考虑高度,初始地面光照强度为0。为了不生成恐怖的怪物,Dicer布置了一些光源,但他不知道是否仍会生成怪物,现在请你帮助Dicer判断。注:光源及秘密物品均为不透明方块,且其上方均不会生成怪物。输入格式第一行是一个T。(1≤T≤100)接下来有T组数据,每一组第一行是N,M,(1≤N,M≤1000),接下来有N行,每行M个字符,代表秘密基地地面放置的方块,0代表空气,#代表秘密物品,Y代表萤石(光照等级为15),H代表火把(光照等级为14),F代表附魔台(光照等级为12),R代表激活的红石火把(光照等级为7)。输出格式输出包含T行,每行如果仍会生成怪物,输出”Yes”,否则输出”No”。样例input22 30Y000#3 4R00#00R00R00outputNoYesinput21 50Y0R02 4Y#0R0000outputYesNoinput15 4Y0F00000000000000000outputNocode:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970#include<bits/stdc++.h>using namespace std;#define ll long long#define pii pair<int,int>const int inf=0x3f3f3f3f;const ll INF=0x3f3f3f3f3f3f3f3f;const int maxn=1000+10;int t,n,m;char mp[maxn][maxn];int vis[maxn][maxn];int d[4][2]={1,0,-1,0,0,1,0,-1};queue<pii>H,F;queue<pii>que;void init(){ while(!que.empty()) que.pop(); while(!H.empty()) H.pop(); while(!F.empty()) F.pop(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) vis[i][j]=0;}bool BFS(){ while(!que.empty()){ int x=que.front().first; int y=que.front().second; que.pop(); if(vis[x][y]==8) break; for(int i=0;i<4;i++){ int xx=x+d[i][0]; int yy=y+d[i][1]; if(xx<=0 || xx>n || yy<=0 || yy>m || vis[xx][yy] || mp[xx][yy]!='0') continue; vis[xx][yy]=vis[x][y]-1; que.push(pii(xx,yy)); while(vis[xx][yy]==14 && (!H.empty())){ que.push(H.front()); H.pop(); } while(vis[xx][yy]==12 && (!F.empty())){ que.push(F.front()); F.pop(); } } } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(vis[i][j]<=7 && mp[i][j]=='0') return false; return true;}int main(){ scanf("%d",&t); while(t--){ scanf("%d %d",&n,&m); init(); for(int i=1;i<=n;i++){ scanf("%s",mp[i]+1); for(int j=1;j<=m;j++){ if(mp[i][j]=='Y') que.push(pii(i,j)),vis[i][j]=15 ;//15 if(mp[i][j]=='H') H.push(pii(i,j)),vis[i][j]=14;//14 if(mp[i][j]=='F') F.push(pii(i,j)),vis[i][j]=12;//12 } } if(BFS()) printf("No\n"); else printf("Yes\n"); } return 0;}连连看Description:众所周知,《连连看》是一个老少皆宜的游戏。《连连看》是由黄兴武创作的一款PC端益智类游戏,只要将相同的两张牌用三根以内的线段连在一起就可以消除,规则简单容易上手。现在呢,Boctorio学长突然想玩连连看了,但不是单纯的玩游戏,他想自己出一局连连看。由于Boctorio学长是一个蒟蒻,他不知道自己出的连连看是否符合能够通过多次操作将其全部消除,所以想要你帮他检查一下他出的连连看是否符合规则。输入格式第一行输入个T,表示T组数据(1≤t≤100)每组数据第一行两个数 n,m ,表示连连看棋盘的长和宽(1≤n,m≤100)接下来 n 行,每行输入 m 个正整数aij,表示 m 个棋子 (1≤aij≤n∗m)。每种棋子只会出现一对,因此数据保证只有一种有效结果。输出格式每组数据输出一行。如果棋盘符合规定,输出”Yes”,否则,输出”No”(不包括引号)。样例input32 21 22 13 41 6 2 34 5 3 14 2 6 54 41 2 3 68 4 7 85 6 5 71 2 3 4outputNoNoYescode:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970#include<bits/stdc++.h>using namespace std;#define ll long longint mp[200][200];int n,m;int sx,sy;int dir[4][2]={{1,0},{0,1},{0,-1},{-1,0}};//分别对应下,右,左,上int check(int x,int y){ if(x<0 || x>n+1 || y<0 || y>m+1) return 1; return 0;}bool judge(int x,int y,int step,int pos){//pos表示上一步方向 if(step>3) return 0;//如果超过了三步,不符合规则 if(mp[x][y]==mp[sx][sy] && pos!=-1){//如果两个字符相等并且不是同一个(由于下面有方向限制,所以两个值不可能相等) mp[x][y]=0;//删去配对字符 mp[sx][sy]=0; return 1; } if(mp[x][y]!=0 && pos!=-1) return 0;//如果不相等并且不是通路,不符合规则 int i,x1,y1; for(i=0;i<4;i++){ if(i+pos==3) continue;//不能有正相反的方向 (0.下 3.上) (1.右 2.左) x1=x+dir[i][0]; y1=y+dir[i][1]; if(check(x1,y1)) continue;//检查是否越界 if(judge(x1,y1,step+(pos==i?0:1),i)){//找到一个就返回 return 1; } } return 0;}int main(){ int t,times,sum; int i,j; scanf("%d",&t); while(t--){ scanf("%d %d",&n,&m); memset(mp,0,sizeof(mp)); for(i=1;i<=n;i++){ for(j=1;j<=m;j++){ scanf("%d",&mp[i][j]); } } sum=0; times=0;//times表示查找的次数,大于等于n*m相当于查找一遍还没有找到 i=j=1; while(sum<n*m && times<n*m){ for(i=1;i<=n;i++){ for(j=1;j<=m;j++){ times++; sx=i,sy=j; if(mp[i][j]!=0 && judge(i,j,0,-1)){ sum+=2; times=0; } } } } if(sum==n*m){ printf("Yes\n"); } else{ printf("No\n"); } } return 0;}Points in rectangleDescription:在二维平面中有一个矩形,它的四个坐标点分别为(0,a),(a,0),(n,n−a),(n−a,n)。你现在有m个点,现在你想知道有多少个点是在这个矩形内的(边上的也算)。输入格式第一行输入n,a(1≤a\<n≤1e3)。第二行一个正整数m(1≤m≤1e3),代表你拥有的点的个数,接下来m行,每行一个点的坐标xi,yi(1≤xi,yi≤1e3)。输出格式第一行输出在矩形内的点的个数,然后输出在矩形内点的坐标,横坐标大的优先,如果横坐标相同,则纵坐标大的优先。如果没有,输出−1。样例input6 151 21 32 33 44 5output44 53 42 31 2code:123456789101112131415161718192021222324252627282930313233343536373839404142434445#include<bits/stdc++.h>using namespace std;int n, a;int m;struct node{ int xo, yo;}biao[10001];node biao1[10001];int cmp(node a, node b){ if(a.xo == b.xo) return a.yo > b.yo; return a.xo > b.xo;}int cnt;bool solve(node point){ return point.yo >= -point.xo + a && point.yo >= point.xo - a && point.yo <= point.xo + a && point.yo <= -point.xo + 2 * n - a;}int main(){ cin >> n >> a >> m; cnt = 0; for(int i = 0; i < m; i ++) { cin >> biao[i].xo >> biao[i].yo; if(solve(biao[i])) { cnt ++; biao1[i].xo = biao[i].xo; biao1[i].yo = biao[i].yo; } } sort(biao1, biao1 + m, cmp); if(cnt == 0) puts("-1"); else { cout << cnt << endl; for(int i = 0; i < cnt; i ++) { cout << biao1[i].xo << " " << biao1[i].yo << endl; } } return 0;}code2:123456789101112131415161718192021222324252627282930313233343536#include<bits/stdc++.h>using namespace std;const int N = 2e3+100;struct point{ long long x,y; bool friend operator<(point a,point b){ if(a.x==b.x) return a.y>b.y; return a.x>b.x; }}p[N];long long n,a;bool check(point P){ return -P.x+a<=P.y&&-P.x+2*n-a>=P.y&&P.x-a<=P.y&&P.x+a>=P.y;}int main(){ //freopen("17.in","r",stdin); //freopen("17.out","w",stdout); vector<point> re; cin>>n>>a; int m; cin>>m; for(int i=1;i<=m;i++){ cin>>p[i].x>>p[i].y; if(check(p[i])) re.push_back(p[i]); } sort(re.begin(),re.end()); if(re.empty()){ cout<<-1<<endl; } else{ cout<<re.size()<<endl; for(auto v:re) cout<<v.x<<' '<<v.y<<endl; } return 0;}Numbers of intervalDescription:code:123456789101112131415161718192021222324252627282930#include<bits/stdc++.h>using namespace std;const int maxx = 1e6;typedef long long ll;ll a[maxx];ll b[maxx];int main(){ int n, k; cin >> n >> k; for(int i = 1; i <= n; i ++) { cin >> a[i]; b[i] = a[i] + b[i - 1]; } ll ans = 0; for(int i = 1; i <= n; i ++) { int pos = lower_bound(b + 1, b + n + 1, k + b[i - 1]) - b; ans += (n - pos + 1); } cout << ans << endl; return 0;}/*这题很巧妙,利用了前缀和与二分查找中的lower_bound首先是前缀和,不断相加前面每一个数的值,(比普通的定义一个变量相加更好用)存值,方便后便用到找到第一个大于等于要求数的值,然后后边的数肯定都大,只要计数就行了*/剪纸Description:中国剪纸是一种用剪刀或刻刀在纸上剪刻花纹,用于装点生活或配合其他民俗活动的民间艺术。在中国,剪纸具有广泛的群众基础,交融于各族人民的社会生活,是各种民俗活动的重要组成部分。其传承赓续的视觉形象和造型格式,蕴涵了丰富的文化历史信息,表达了广大民众的社会认以、道德观念、实践经验、生活理想和审美情趣,具有认知、教化、表意、抒情、娱乐、交往等多重社会价值。2006年5月20日,剪纸艺术遗产经国务院批准列入第一批国家级非物质文化遗产名录 。2009年9月28日至10月2日举行的联合国教科文组织保护非物质文化遗产政府间委员会第四次会议上,中国申报的中国剪纸项目入选“人类非物质文化遗产代表作名录”。剪窗花最基本的操作为将剪纸进行多次对折,然后对对折之后的纸进行裁剪,展开后就是一个精美的艺术品。现在我们对问题进行化简,我们利用如下方法将一张形状矩形的纸按照对阵轴进行对折:假设剪后的形状为一个三角形,则展开效果为:现在给你一个对折两次且剪切后的图形,请你给出展开的图形形状。输入格式多组输入,处理到文件结束。每组输入第一行两个数字n,m(1≤n,m≤100)。接下来n行,每行m个字符,表示对折且剪切后的图形。保证输入字符只包含 ‘.’ 和 ‘’ 。输出格式输出展开后的图形。样例input3 3**. ..…output…….....**..**.....……code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354//F#include<bits/stdc++.h>using namespace std;const int maxx = 1000+10;char mmp[maxx][maxx];int main(){ int n, m; while(~scanf("%d %d",&n, &m)) { memset(mmp, '.', sizeof mmp); for(int i = 0; i < n; i ++) { for(int j = 0; j < m; j ++) { cin >> mmp[i][j]; if(mmp[i][j] == '*') { mmp[i + n][j + m] = '*'; mmp[i][j] = '.'; } // cout << a[i][j]; } // puts("");////// } for(int i = 0; i < n * 2; i ++) { for(int j = 0; j < m * 2; j ++) { if(mmp[i][j] != '*') mmp[i][j] = '.'; if(mmp[i][j] == '*') { mmp[2 * n - i - 1][j] = '*'; mmp[i][2 * m - j - 1] = '*'; mmp[2 * n - i - 1][2 * m - j - 1] = '*'; } } } for(int i = 0; i < 2 * n; i ++) { for(int j = 0; j < 2 * m; j ++) { cout << mmp[i][j]; } puts(""); } } return 0;}Fake hpuoj predictorDescription:总所周知,HPU(Harmonious and Peaceful University) Online Judge具有一个强大的的rating(积分)系统,它采用的是国际上权威的ELO等级分制度(ELO Rating System),LOL,守望先锋,codeforces,topcoder等知名游戏的排行均是采用此制度。具体算法为:其中R(A)和R(B)为选手A和B初始的rating,那么E(A)和E(B)即为这两者进行对战后A和B各自获胜的期望。本场比赛的积分公式即为RA代表上轮比赛结束后的积分。K为积分系数,对于不同等级的选手的K是不同的。SA代表比赛实际总得分,对于每局比赛来说,每赢一个人就会加1分,输了不扣分。EAi代表A与第i个选手比赛获胜的期望。对于HPU Online Judge,用户等级表为:codancer有一个成为Grand Master的梦想,已知他的初始rating为0,他总共参加了m场比赛,对于每场比赛有一个榜单,对于codancer来说,排在他前面的人都打败了他,排在他后面的人都输给了他,因此你可以通过和每个参加比赛的选手比较计算出总得分SA和总期望∑EAi。那么最终codancer打完本场比赛后的rating为现在他打完了这m场比赛后他迫切的想知道自己的rating变为了多少(因为管理员太懒了,已经鸽了m场的rating计算了),现在他想让你帮他写一个预测器来预测一下。输入格式单组输入,第一行输入一个m(1≤m≤100),代表codancer参加的比赛的数量。接下来对于每场比赛:第一行输入一个整数n代表有n(1≤n≤100)个人参加的比赛。接下来n行每行输入一个字符串和数字,代表参赛选手的用户名和他的rating,codancer即为他自己的用户名(用户名长度不超过20),假如输入的名字为codancer,则不用输入数字(其他参赛选手的rating是不会更新的,因为管理员太懒了)。输出格式输出codancer最终的rating,向上取整。样例input35tourist 2000capryang 1900boctorio 1800dicer 1800codancer2codancerrookie 2002wzy 1500codanceroutput12code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253#include<bits/stdc++.h>using namespace std;const int maxn=1000+10;int n,m,a;struct node{ char name[30]; double rating;}p[maxn];double cal(double rating){ if(rating<1350) return 15.0; else if(rating<1500) return 20.0; else if(rating<1600) return 25.0; else if(rating<1700) return 30.0; else if(rating<1800) return 35.0; else return 50.0;}double Rating(double rating){ double k=cal(rating); double ea=0,sa=0; for(int i=0;i<n;i++){ if(strcmp(p[i].name,"codancer")==0) continue; ea+=1.0/(1.0+pow(10,(p[i].rating-rating)/400.0)); } for(int i=0;i<n;i++){ if(strcmp(p[i].name,"codancer")==0){ sa=n-1-i; break; } } double now_rating=rating+k*(sa-ea);// return now_rating; return ceil(now_rating);}int main(){ int m; scanf("%d",&m); double codancerNB_rating=0.0; while(m--){ scanf("%d",&n); for(int i=0;i<n;i++){ scanf("%s",p[i].name); if(strcmp(p[i].name,"codancer")==0){ p[i].rating=codancerNB_rating; continue; } scanf("%lf",&p[i].rating); } codancerNB_rating=Rating(codancerNB_rating); } printf("%.0lf\n",ceil(codancerNB_rating)); return 0;}花花与三猫CatliveDescription:“大佬”中分和“呆B”李白正在玩一个游戏,游戏规则是这样的:游戏刚开始的时候,中分和李白相距L步,相对而望。老父亲和老母亲手中各有一个M个面的均匀骰子。(也就是说可以随机生成[1,m]内的任意一个数字,且概率均等)在每个回合开始的时候,老父亲和老母亲都会掷一下手中的骰子。当老父亲的骰子掷到1的时候,中分可以向李白走一步。当老母亲的骰子掷到m的时候,李白可以向中分走一步。当中分和李白相遇的时候,游戏结束。可是老父亲和老母亲刚刚拍完新节目,他们太累了,不想做这个游戏,但是他们还很想知道,这个游戏平均需要多少次才能结束。聪明的你,能告诉他们吗?结果是一个实数s,可以证明s能被表示成一个分数 qp,请输出q⋅p−1,其中q−1表示q在模109+7意义下的逆元。输入格式第一行是一个正整数 T(1≤T≤1000),表示测试样例的组数。接下来T行,每行两个正整数L,M(1≤L,M≤1000),含义如题面描述。输出格式输出包括T行,每行一个答案。样例input21 22 1output11code:123456789101112131415#include<bits/stdc++.h>using namespace std;const int MOD = 1e9 + 7;int main(){ int T; scanf("%d", &T); int L, M; while(T--) { scanf("%d %d", &L, &M); printf("%lld\n", 1LL * L * M * 500000004 % MOD); } return 0;}code2:123456789101112131415161718192021222324252627//为啥多了几行,学长的意思是打cf的,防止被hack,哈哈#include<bits/stdc++.h>const int MOD = 1e9 + 7;int qpow(int a, int b, int mod){ int res = 1; while(b){ if(b&1) res = 1LL * res * a % mod; a = 1LL * a * a % mod; b >>= 1; } return res;}int inv(int p, int mod){ return qpow(p, mod - 2, mod);}int main(){ int T; scanf("%d", &T); int L, M; while(T--){ scanf("%d %d", &L, &M); printf("%lld\n", 1LL * L * M * 500000004 % MOD); }}Same StringDescription:有两个只由小写字母组成的长度为n的字符串s1,s2和m组字母对应关系,每一组关系由两个字母c1和c2组成,代表c1可以直接变成c2,你需要判断s1是否可以通过这m组关系转换为s2。输入格式第一行输入一个n(1≤n≤100),代表字符串的长度。第二行和第三行输入两个字符串s1,s2。第四行输入一个m(1≤m≤325),代表有m组关系。接下来m行,第i行两个字符ui,vi,代表ui可以直接变为vi。输出格式如果s1可以通过这些m组关系转化变为s2,输出”YES”,否则输出”NO”。样例input6aabbcccdbcad4a cc aa db coutputYEScode:1234567891011121314151617181920212223242526272829303132333435363738#include<bits/stdc++.h>using namespace std;const int N = 1e6+100;typedef long long ll;bool f[26][26];int main(){ int n,m; string s1,s2; cin>>n>>s1>>s2; cin>>m; char u,v; for(int i=1;i<=m;i++){ cin>>u>>v; f[u-'a'][v-'a']=1; } for(int j=0;j<26;j++){ for(int i=0;i<26;i++){ for(int k=0;k<26;k++){ f[i][k]|=(f[i][j]&f[j][k]); } } } bool check=0; for(int i=0;i<n;i++){ if(s1[i]!=s2[i]){ if(f[s1[i]-'a'][s2[i]-'a']==0){ check=1;break; } } } if(check){ puts("NO"); } else puts("YES"); // } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
<tag>图论</tag>
<tag>搜素算法</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day9]]></title>
<url>%2F2019%2F07%2F26%2FDay9%2F</url>
<content type="text"><![CDATA[Day9今天是 dfs 和 bfs 加训继续学习 dfs 和 bfs,毕竟这一块还是非常重要的OJ链接:https://vjudge.net/contest/314510#overviewKnight MovesProblem DescriptionBackgroundMr Somurolov, fabulous chess-gamer indeed, asserts that no one else but him can move knights from one position to another so fast. Can you beat him?The ProblemYour task is to write a program to calculate the minimum number of moves needed for a knight to reach one point from another, so that you have the chance to be faster than Somurolov.For people not familiar with chess, the possible knight moves are shown in Figure 1.InputThe input begins with the number n of scenarios on a single line by itself.Next follow n scenarios. Each scenario consists of three lines containing integer numbers. The first line specifies the length l of a side of the chess board (4 <= l <= 300). The entire board has size l l. The second and third line contain pair of integers {0, …, l-1}{0, …, l-1} specifying the starting and ending position of the knight on the board. The integers are separated by a single blank. You can assume that the positions are valid positions on the chess board of that scenario.OutputFor each scenario of the input you have to calculate the minimal amount of knight moves which are necessary to move from the starting point to the ending point. If starting point and ending point are equal,distance is zero. The distance must be written on a single line.123456789101112131415Sample Input380 07 01000 030 50101 11 1Sample Output5280code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<queue>#include<stack>#include<vector>#include<cmath>using namespace std;const int mod = 1e9;const int maxx = 1e5 + 10;int c, d;int ans, n;int vis[400][400];int dd[8][2] = { -2, 1, -1, 2, 1, 2, 2, 1, -2, -1, -1, -2, 1, -2, 2, -1};struct node{ int x, y, step;};void bfs(int x, int y){ ans = 0; memset(vis, 0, sizeof vis); queue<node> q; node e1, e2; e1.x = x, e1.y = y, e1.step = 0; q.push(e1); vis[e1.x][e1.y] = 1; while(!q.empty()) { e1 = q.front(); q.pop(); if(e1.x == c && e1.y == d) { ans = e1.step; break; } for(int i = 0; i < 8; i ++) { e2.x = e1.x + dd[i][0]; e2.y = e1.y + dd[i][1]; if(e2.x >= 0 && e2.y >= 0 && e2.x < n && e2.y < n && vis[e2.x][e2.y] == 0) { vis[e2.x][e2.y] = 1; e2.step = e1.step + 1; q.push(e2); } } } cout << ans << endl;}int main(){ int T; int a, b; cin >> T; while(T --) { cin >> n; cin >> a >> b >> c >> d; bfs(a, b); } return 0;}变形课Problem Description呃……变形课上Harry碰到了一点小麻烦,因为他并不像Hermione那样能够记住所有的咒语而随意的将一个棒球变成刺猬什么的,但是他发现了变形咒语的一个统一规律:如果咒语是以a开头b结尾的一个单词,那么它的作用就恰好是使A物体变成B物体.Harry已经将他所会的所有咒语都列成了一个表,他想让你帮忙计算一下他是否能完成老师的作业,将一个B(ball)变成一个M(Mouse),你知道,如果他自己不能完成的话,他就只好向Hermione请教,并且被迫听一大堆好好学习的道理.Input测试数据有多组。每组有多行,每行一个单词,仅包括小写字母,是Harry所会的所有咒语.数字0表示一组输入结束.Output如果Harry可以完成他的作业,就输出”Yes.”,否则就输出”No.”(不要忽略了句号)12345678910111213141516Sample Inputsosoonrivergoesthemgotmoonbeginbig0Sample OutputYes.HintHarry 可以念这个咒语:"big-got-them".code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<queue>#include<stack>#include<vector>#include<cmath>using namespace std;const int mod = 1e9;const int maxx = 1e5 + 10;string ss;bool vis[1000 + 10];int i;int flag;struct node{ int x, y;}a[1000 + 10];void dfs(int x){ if(a[x].y == 'm') { flag = 1; return; } for(int j = 0; j < i; j ++) { if(a[x].y == a[j].x && vis[j] == 0) { vis[j] = 1; dfs(j); } }}int main(){ while(cin >> ss) { memset(vis, 0, sizeof vis); flag = 0; i = 0; while(cin >> ss) { if(ss[0] != '0') { a[i].x = ss[0]; a[i].y = ss[ss.size() - 1]; i ++; } else break; for(int j = 0; j < i; j ++) { if(a[j].x == 'b') { vis[j] = 1; dfs(j); } } } if(flag) puts("Yes."); else puts("No."); } return 0;}PetProblem Description一天早上小明醒来时发现他的宠物仓鼠不见了。 他在房间寻找但是没找到仓鼠。 他想用奶酪诱饵去找回仓鼠。 他把奶酪诱饵放在房间并且等待了好几天。 但是可怜的小明除了老鼠和蟑螂没见到任何东西。 他找到学校的地图发现地图上没有环路,并且学校里的每个站点都可以从他的房间到达。 奶酪诱饵的手册提到在距离D之内宠物必定会被吸引回来. 你的任务是帮助小明从给定的地图中有多少可能的站点是仓鼠的藏身处. 假定仓鼠一直藏在学校的某个站点并且两个相邻站点间的距离都是1个单位。Input输入包含多组数据。 第一行一个整数T (0<T<=10), 表示测试数据的组数。 每组数据, 第一行包含两个整数 N (0<N<=100000) 和 D(0<D<N). N 是学校里的站点数, D 是诱饵的影响距离。 下面 N-1行为地图描述, 每行一对 x 和 y(0<=x,y<N), 用一个空格隔开, 表示x和y两个站点是相邻的。小明的房间用0表示。Output对于每组数据,输出可能找到仓鼠的站点数。1234567891011121314Sample Input110 20 10 20 31 41 52 63 74 86 9Sample Output2code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121bfs解法:#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<queue>#include<stack>#include<vector>#include<cmath>using namespace std;const int mod = 1e9;const int maxx = 1e5 + 10;vector<int> v[maxx];int n, d;bool vis[maxx];int dis[maxx];void bfs(){ memset(vis, 0, sizeof vis); memset(dis, 0, sizeof dis); queue<int> q; q.push(0); vis[0] = 1; dis[0] = 0; int cnt = 0; while(!q.empty()) { int f = q.front(); q.pop(); if(dis[f] > d) { cnt ++; } for(int i = 0; i < v[f].size(); i ++) { if(vis[v[f][i]] == 0) { dis[v[f][i]] = dis[f] + 1; vis[v[f][i]] = 1; q.push(v[f][i]); } } } printf("%d\n",cnt);}int main(){// ios::sync_with_stdio(false); int T; int a, b; while(~scanf("%d",&T)) { while(T --) { scanf("%d %d",&n, &d); for(int i = 0; i < n; i ++) v[i].clear(); for(int i = 0;i < n - 1; i ++) { scanf("%d %d",&a, &b); v[a].push_back(b); } bfs(); } } return 0;}dfs解法:#include <bits/stdc++.h>using namespace std;const int maxn = 1e5 + 50 ;vector<int>G[maxn] ;int ans ;int n ,m ;int vis[maxn] ;void dfs(int st ,int l){ if ( l > m ) ans ++ ; int len = G[st].size() ; for (int i = 0 ; i < len ; i ++ ) { if ( !vis[G[st][i]] ) { dfs(G[st][i] ,l + 1 ) ; vis[G[st][i]] = 1; } }}int main() { int t ; while(scanf("%d",&t)!=EOF) { while ( t -- ) { ans = 0 ; int a ,b ; scanf("%d %d",&n ,&m); for (int i = 0 ; i <= n ; i ++ ) G[i].clear() ,vis[i] = 0 ; for (int i = 1 ; i <= n - 1 ; i ++ ) { scanf("%d %d",&a ,&b ) ; G[a].push_back(b) ; //G[b].push_back(a) ; } dfs(0 ,0 ) ; printf("%d\n",ans) ; } } return 0;}蜘蛛牌Problem Description蜘蛛牌是windows xp操作系统自带的一款纸牌游戏,游戏规则是这样的:只能将牌拖到比她大一的牌上面(A最小,K最大),如果拖动的牌上有按顺序排好的牌时,那么这些牌也跟着一起移动,游戏的目的是将所有的牌按同一花色从小到大排好,为了简单起见,我们的游戏只有同一花色的10张牌,从A到10,且随机的在一行上展开,编号从1到10,把第i号上的牌移到第j号牌上,移动距离为abs(i-j),现在你要做的是求出完成游戏的最小移动距离。Input第一个输入数据是T,表示数据的组数。每组数据有一行,10个输入数据,数据的范围是[1,10],分别表示A到10,我们保证每组数据都是合法的。Output对应每组数据输出最小移动距离。12345Sample Input11 2 3 4 5 6 7 8 9 10Sample Output9code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859思路:桶排原理记录每张牌的位置,遍历每张牌,枚举所有可能位置。将牌的大小作为下标。然后依次遍历。。。#include <iostream>#include <cstring>#include <cstdio>#include <cstdlib>using namespace std;const int MAX = 0x3f3f3f3f;char a[100];char visit[100];int ans;void dfs(int num, int sum){ if (num==9) { if(sum<ans) { ans = sum; } return ; } for(int i=1; i<10; i++) { if(visit[i]==0) { visit[i] = 1; for(int j=i+1; j<=10; j++) { if(visit[j]==0) { dfs(num+1, sum + abs(a[j]-a[i])); break; } } visit[i] = 0; } }}int main(){ int T, x; scanf("%d", &T); while(T--) { for(int i=1; i<=10; i++) { scanf("%d", &x); a[x] = i; } memset(visit, 0, sizeof(visit)); ans = MAX; dfs(0, 0); printf("%d\n", ans); } return 0;}逃离迷宫Problem Description给定一个m × n (m行, n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,gloria可以穿越,有些地方是障碍,她必须绕行,从迷宫的一个位置,只能走到与它相邻的4个位置中,当然在行走过程中,gloria不能走到迷宫外面去。令人头痛的是,gloria是个没什么方向感的人,因此,她在行走过程中,不能转太多弯了,否则她会晕倒的。我们假定给定的两个位置都是空地,初始时,gloria所面向的方向未定,她可以选择4个方向的任何一个出发,而不算成一次转弯。gloria能从一个位置走到另外一个位置吗?Input第1行为一个整数t (1 ≤ t ≤ 100),表示测试数据的个数,接下来为t组测试数据,每组测试数据中,第1行为两个整数m, n (1 ≤ m, n ≤ 100),分别表示迷宫的行数和列数,接下来m行,每行包括n个字符,其中字符’.’表示该位置为空地,字符’*’表示该位置为障碍,输入数据中只有这两种字符,每组测试数据的最后一行为5个整数k, x 1, y 1, x 2, y 2 (1 ≤ k ≤ 10, 1 ≤ x 1, x 2 ≤ n, 1 ≤ y 1, y 2 ≤ m),其中k表示gloria最多能转的弯数,(x 1, y 1), (x 2, y 2)表示两个位置,其中x 1,x 2对应列,y 1, y 2对应行。Output每组测试数据对应为一行,若gloria能从一个位置走到另外一个位置,输出“yes”,否则输出“no”。12345678910111213141516171819Sample Input25 5...***.**...........*....1 1 1 1 35 5...***.**...........*....2 1 1 1 3Sample Outputnoyescode:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<queue>#include<stack>#include<vector>#include<cmath>using namespace std;const int mod = 1e9;const int maxx = 1e2 + 10;int n, m, a1, b1, a2, b2, k;char a[maxx][maxx];bool vis[maxx][maxx];int flag;int d[4][2] = { 1, 0, -1, 0, 0, 1, 0, -1};struct node{ int x, y, step;};void bfs(){ memset(vis, 0, sizeof vis); queue<node> q; node e1, e2, e3; e1.x = a1 - 1, e1.y = b1 - 1, e1.step = -1; q.push(e1); vis[e1.x][e1.y] = 1; while(!q.empty()) { e1 = q.front(); q.pop(); if(e1.x == a2 - 1 && e1.y == b2 - 1 && e1.step <= k) { flag = 1; return; } for(int i = 0; i < 4; i ++) { e2.x = e1.x + d[i][0]; e2.y = e1.y + d[i][1]; while(e2.x >= 0 && e2.y >= 0 && e2.x < n && e2.y < m && a[e2.x][e2.y] == '.') { if(vis[e2.x][e2.y] == 0) { e2.step = e1.step + 1; vis[e2.x][e2.y] = 1; q.push(e2); } e3.x = e2.x + d[i][0]; e3.y = e2.y + d[i][1]; e2 = e3; } } }}int main(){ int T; scanf("%d",&T); while(T --) { scanf("%d %d",&n, &m); for(int i = 0; i < n; i ++) for(int j = 0; j < m; j ++) { cin >> a[i][j]; } scanf("%d %d %d %d %d",&k, &b1, &a1, &b2, &a2); flag = 0; bfs(); if(flag) puts("yes"); else puts("no"); } return 0;}Kaitou Kid - The Phantom Thief (2)Problem Description破解字迷之后,你得知Kid将会在展览开始后T分钟内盗取至少一颗宝石,并离开展馆。整个展馆呈矩形分布,划分为N*M个区域,有唯一的入口和出口(不能从出口进入,同样不能从入口出去)。由某个区域可直接移动至相邻四个区域中的一个,且最快需要一分钟。假设Kid进入放有宝石的区域即可盗取宝石,无需耗时。问至少要封锁几个区域(可以封锁放有宝石的区域,但不能封锁入口和出口)才能保证Kid无法完成任务。Input输入的第一行有一个整数C,代表有C组测试数据。每组测试数据的第一行有三个整数N,M,T(2<=N,M<=8,T>0)。接下来N行M列为展馆布置图,其中包括:‘S’:入口‘E’:出口‘J’:放有宝石的区域,至少出现一次‘.’:空白区域‘#’:墙Output对每组测试数据,输出至少要封锁的区域数。1234567891011121314151617Sample Input25 5 5SJJJJ..##J.JJJJ.J...EJ...5 5 6SJJJJ..##J.JJJJ.J...EJ...Sample Output02code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394#include<iostream>#include<cstring>#include<queue>using namespace std;char mapp[10][10];int visit[10][10];int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};int n,m,o;int sx,sy,ex,ey;int flag;struct stu{ int x,y; int d; int flag;};int bfs(){ memset(visit,0,sizeof(visit)); stu x,y; queue<stu>root; x.x=sx;x.y=sy;x.flag=1;x.d=0; visit[x.x][x.y]=1; root.push(x); while(root.size()) { x=root.front(); root.pop(); if(x.x==ex&&x.y==ey&&x.flag==2&&x.d<=o) return 0; for(int i=0;i<4;i++) { y.x=x.x+dir[i][0]; y.y=x.y+dir[i][1]; y.d=x.d+1; if(mapp[y.x][y.y]=='J') y.flag=2; else y.flag=x.flag; if(y.x<0||y.x>=n||y.y<0||y.y>=m||visit[y.x][y.y]==y.flag||mapp[y.x][y.y]=='#'||y.d>o) continue; visit[y.x][y.y]=y.flag; root.push(y); } } return 1;}void dfs(int x){ if(bfs()) flag=1; for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { char ma=mapp[i][j]; if(ma=='.'||ma=='J') { mapp[i][j]='#'; if(x>0) dfs(x-1); if(flag) return; mapp[i][j]=ma; } } }}int main(){ cin.sync_with_stdio(false); int t; cin>>t; while(t--) { cin>>n>>m>>o; for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { cin>>mapp[i][j]; if(mapp[i][j]=='S') sx=i,sy=j; if(mapp[i][j]=='E') ex=i,ey=j; } } flag=0; re=1<<30; for(int i=0;i<=4;i++) { dfs(i); if(flag) { cout<<i<<endl; break; } } } return 0;}A计划Problem Description可怜的公主在一次次被魔王掳走一次次被骑士们救回来之后,而今,不幸的她再一次面临生命的考验。魔王已经发出消息说将在T时刻吃掉公主,因为他听信谣言说吃公主的肉也能长生不老。年迈的国王正是心急如焚,告招天下勇士来拯救公主。不过公主早已习以为常,她深信智勇的骑士LJ肯定能将她救出。现据密探所报,公主被关在一个两层的迷宫里,迷宫的入口是S(0,0,0),公主的位置用P表示,时空传输机用#表示,墙用表示,平地用.表示。骑士们一进入时空传输机就会被转到另一层的相对位置,但如果被转到的位置是墙的话,那骑士们就会被撞死。骑士们在一层中只能前后左右移动,每移动一格花1时刻。层间的移动只能通过时空传输机,且不需要任何时间。Input输入的第一行C表示共有C个测试数据,每个测试数据的前一行有三个整数N,M,T。 N,M迷宫的大小NM(1 <= N,M <=10)。T如上所意。接下去的前NM表示迷宫的第一层的布置情况,后NM表示迷宫第二层的布置情况。Output如果骑士们能够在T时刻能找到公主就输出“YES”,否则输出“NO”。12345678910111213141516Sample Input15 5 14S*#*..#........****....#...*.P#.*..***.....*.*.#..Sample OutputYEScode:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<queue>#include<stack>#include<vector>#include<cmath>using namespace std;const int mod = 1e9;const int maxx = 1e5 + 10;int n, m, p;int ans;char a[2][30][30];bool vis[2][30][30];//int step[2][30][30];struct node{ int x, y, z; int t; friend bool operator < (node a, node b) { return a.t > b.t; }}e;int d[4][2] = { 0, 1, 0, -1, 1, 0, -1, 0};int bfs(){ memset(vis, 0, sizeof vis); queue<node> q; node e1, e2; e1.x = 0, e1.y = 0, e1.z = 0, e1.t = 0; q.push(e1); vis[e1.x][e1.y][e1.z] = 1; while(!q.empty()) { e1 = q.front(); q.pop(); if(e1.z == e.z && e1.x == e.x && e1.y == e.y) { return e1.t; } for(int i = 0; i < 4; i ++) { e2.x = e1.x + d[i][0]; e2.y = e1.y + d[i][1]; e2.z = e1.z; if(e2.x >= 0 && e2.y >= 0 && e2.x < n && e2.y < m && vis[e2.z][e2.x][e2.y] == 0 && a[e2.z][e2.x][e2.y] != '*') { if(a[e2.z][e2.x][e2.y] == '#') { e2.z = 1 - e2.z; if(a[e2.z][e2.x][e2.y] == '*' || a[e2.z][e2.x][e2.y] == '#') continue; } e2.t = e1.t + 1; if(e2.t > p) continue;//必须剪枝 q.push(e2); vis[e2.z][e2.x][e2.y] = 1; } } } return -1;}int main(){ int T; cin >> T; while(T --) { cin >> n >> m >> p; for(int i = 0; i < 2; i ++) { for(int j = 0; j < n; j ++) { for(int k = 0; k < m; k ++) { cin >> a[i][j][k]; if(a[i][j][k] == 'P') { e.z = i; e.x = j; e.y = k; } } } } ans = bfs();// cout << ans << endl; if(ans != -1 && ans <= p) puts("YES"); else puts("NO"); } return 0;}NightmareProblem DescriptionIgnatius had a nightmare last night. He found himself in a labyrinth with a time bomb on him. The labyrinth has an exit, Ignatius should get out of the labyrinth before the bomb explodes. The initial exploding time of the bomb is set to 6 minutes. To prevent the bomb from exploding by shake, Ignatius had to move slowly, that is to move from one area to the nearest area(that is, if Ignatius stands on (x,y) now, he could only on (x+1,y), (x-1,y), (x,y+1), or (x,y-1) in the next minute) takes him 1 minute. Some area in the labyrinth contains a Bomb-Reset-Equipment. They could reset the exploding time to 6 minutes.Given the layout of the labyrinth and Ignatius’ start position, please tell Ignatius whether he could get out of the labyrinth, if he could, output the minimum time that he has to use to find the exit of the labyrinth, else output -1.Here are some rules:We can assume the labyrinth is a 2 array.Each minute, Ignatius could only get to one of the nearest area, and he should not walk out of the border, of course he could not walk on a wall, too.If Ignatius get to the exit when the exploding time turns to 0, he can’t get out of the labyrinth.If Ignatius get to the area which contains Bomb-Rest-Equipment when the exploding time turns to 0, he can’t use the equipment to reset the bomb.A Bomb-Reset-Equipment can be used as many times as you wish, if it is needed, Ignatius can get to any areas in the labyrinth as many times as you wish.The time to reset the exploding time can be ignore, in other words, if Ignatius get to an area which contain Bomb-Rest-Equipment, and the exploding time is larger than 0, the exploding time would be reset to 6.InputThe input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow.Each test case starts with two integers N and M(1<=N,Mm=8) which indicate the size of the labyrinth. Then N lines follow, each line contains M integers. The array indicates the layout of the labyrinth.There are five integers which indicate the different type of area in the labyrinth:0: The area is a wall, Ignatius should not walk on it.1: The area contains nothing, Ignatius can walk on it.2: Ignatius’ start position, Ignatius starts his escape from this position.3: The exit of the labyrinth, Ignatius’ target position.4: The area contains a Bomb-Reset-Equipment, Ignatius can delay the exploding time by walking to these areas.OutputFor each test case, if Ignatius can get out of the labyrinth, you should output the minimum time he needs, else you should just output -1.123456789101112131415161718192021Sample Input33 32 1 11 1 01 1 34 82 1 1 0 1 1 1 01 0 4 1 1 0 4 11 0 0 0 0 0 0 11 1 1 4 1 1 1 35 81 2 1 1 1 1 1 41 0 0 0 1 0 0 11 4 1 0 1 1 0 11 0 0 0 0 3 0 11 1 4 1 1 1 1 1Sample Output4-113code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364#include<bits/stdc++.h>using namespace std;int n,m,a[10][10];struct node{ int x,y,step,time;};int d[4][2]={1,0,0,1,0,-1,-1,0};int ans;node now,mid;void bfs(){ queue<node> q; q.push(now); while(!q.empty()) {// cout<<"?"<<endl; now=q.front(); q.pop(); if(now.time<=0) continue; if(a[now.x][now.y]==3) { ans=now.step; return ; } for(int i=0;i<4;i++) { mid.x=now.x+d[i][0]; mid.y=now.y+d[i][1]; mid.step=now.step+1; mid.time=now.time-1; if(mid.x<0||mid.x>=n||mid.y<0||mid.y>=m||mid.time<=0||a[mid.x][mid.y]==0) continue; if(a[mid.x][mid.y]==4) { a[mid.x][mid.y]=0; mid.time=6; } q.push(mid); } }}int main(){ int t; cin>>t; while(t--) { ans=-1; cin>>n>>m; for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { cin>>a[i][j]; if(a[i][j]==2) { now.x=i,now.y=j,now.step=0,now.time=6; } } } bfs(); cout<<ans<<endl; }}胜利大逃亡Problem DescriptionIgnatius被魔王抓走了,有一天魔王出差去了,这可是Ignatius逃亡的好机会.魔王住在一个城堡里,城堡是一个ABC的立方体,可以被表示成A个B*C的矩阵,刚开始Ignatius被关在(0,0,0)的位置,离开城堡的门在(A-1,B-1,C-1)的位置,现在知道魔王将在T分钟后回到城堡,Ignatius每分钟能从一个坐标走到相邻的六个坐标中的其中一个.现在给你城堡的地图,请你计算出Ignatius能否在魔王回来前离开城堡(只要走到出口就算离开城堡,如果走到出口的时候魔王刚好回来也算逃亡成功),如果可以请输出需要多少分钟才能离开,如果不能则输出-1.Input输入数据的第一行是一个正整数K,表明测试数据的数量.每组测试数据的第一行是四个正整数A,B,C和T(1<=A,B,C<=50,1<=T<=1000),它们分别代表城堡的大小和魔王回来的时间.然后是A块输入数据(先是第0块,然后是第1块,第2块……),每块输入数据有B行,每行有C个正整数,代表迷宫的布局,其中0代表路,1代表墙.(如果对输入描述不清楚,可以参考Sample Input中的迷宫描述,它表示的就是上图中的迷宫)特别注意:本题的测试数据非常大,请使用scanf输入,我不能保证使用cin能不超时.在本OJ上请使用Visual C++提交.Output对于每组测试数据,如果Ignatius能够在魔王回来前离开城堡,那么请输出他最少需要多少分钟,否则输出-1.1234567891011121314Sample Input13 3 4 200 1 1 10 0 1 10 1 1 11 1 1 11 0 0 10 1 1 10 0 0 00 1 1 00 1 1 0Sample Output11code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364#include<bits/stdc++.h>using namespace std;int a,b,c,k;int s[51][51][51];int vis[51][51][51];struct node{ int x,y,z,step;};node mz,mid,ne;int d[6][3]={1,0,0, -1,0,0, 0,1,0, 0,-1,0, 0,0,1,0,0,-1},ans;void bfs(){ mz.x=mz.y=mz.z=mz.step=0; queue<node> q; q.push(mz); vis[0][0][0]=1; while(!q.empty()) { mid=q.front(); q.pop(); if(mid.step>k) { return ; } if(mid.x==a-1&&mid.y==b-1&&mid.z==c-1&&mid.step<=k) { ans=mid.step; return ; } for(int i=0;i<6;i++) { ne.x=mid.x+d[i][0]; ne.y=mid.y+d[i][1]; ne.z=mid.z+d[i][2]; if(ne.x<0||ne.x>=a||ne.y<0||ne.y>=b||ne.z<0||ne.z>=c||vis[ne.x][ne.y][ne.z]||s[ne.x][ne.y][ne.z]==1) continue; ne.step=mid.step+1; vis[ne.x][ne.y][ne.z]=1; q.push(ne); } }}int main(){ int t;scanf("%d",&t); while(t--) { memset(vis,0,sizeof(vis)); ans=-1; scanf("%d %d %d %d",&a,&b,&c,&k); for(int i=0;i<a;i++) { for(int j=0;j<b;j++) { for(int k=0;k<c;k++) { scanf("%1d",&s[i][j][k]); } } } bfs(); printf("%d\n",ans); }}A strange liftProblem Description计院有一个bug电梯,可能是hyk造的,很多bug,电梯只有两个按钮,“上”和“下”,电梯每层都可以停,每层都有一个数字Ki(0<=Ki<=n),当你在一层楼,你按“上”键会到1+K1层,你按“下”键会到1-K1层。当然,电梯不能升到N以上,也不能降到1以下。例如,有一个五层楼的建筑,k1=3,k2=3,k3=1,k4=2,k5=5。从第一层开始,你可以按“上”按钮,然后你就上到第四层,如果在第一层按“下”按钮,电梯就不能做到,因为你知道它不能下到负二层。负二楼不存在。那么,你想从A层到B层,你至少要按多少次“上”或“下”按钮呢?Input输入由几个测试用例组成,每个测试用例包含两行。第一行包含三个整数n,a,b(1<=n,a,b<=200),如上文所述,第二行包含n个整数k1,k2,….kn。单个0表示输入的结束。Output对于每种情况下的输入输出一个整数,当你在A层,你必须按下按钮的最少次数,你想去B层。如果你不能到达B层,打印“-1”。123456Sample Input5 1 53 3 1 2 50Sample Output3code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152#include<bits/stdc++.h>using namespace std;int n,a,b,meizi;int s[250][250],ans;int vis[250],step[250];void bfs(int x){ queue<int> q; q.push(x); vis[x]=1,step[x]=0; while(!q.empty()) { int mid=q.front(); q.pop();// cout<<mid<<endl; if(mid==b) {// cout<<"?"<<endl; ans=step[mid]; return ; } for(int i=1;i<=n;i++) {// cout<<x<<" "<<i<<" "<<s[x][i]<<endl; if(s[mid][i]&&vis[i]==0) { q.push(i); vis[i]=1; step[i]=step[mid]+1; } } }}int main(){ while(cin>>n&&n) { memset(vis,0,sizeof(vis)); memset(step,0,sizeof(step)); memset(s,0,sizeof(s)); ans=-1; cin>>a>>b; for(int i=1;i<=n;i++) { cin>>meizi; if(i+meizi>=1&&i+meizi<=n) s[i][meizi+i]=1; if(i-meizi>=1&&i-meizi<=n) s[i][i-meizi]=1; } bfs(a); cout<<ans<<endl; }}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
<tag>图论</tag>
<tag>搜素算法</tag>
</tags>
</entry>
<entry>
<title><![CDATA[自我感想]]></title>
<url>%2F2019%2F07%2F25%2F%E5%BF%83%E6%80%81%2F</url>
<content type="text"><![CDATA[心态人们常说:心态决定命运今天,写下这篇文章也是想给自己指明方向面朝大海,春暖花开学习的目的说实话,每个人都喜欢玩乐,但是,学习,只是让自己去获得某样东西也许,可以是知识,也可以是技能,又或者是友谊等等也有人说,学习是件痛苦的事但我想说的只有一点,那就是别逼着自己去学习在学习之前,思考并问一下自己,是不是真的想获得某样东西~可以说,没有人不想获得“超能力”,但是这些“超能力”又该怎么来那就是我们的学习很多人把学习固定化了,认为那就是学习书本上的知识那样错了!学习不该有范围,因为学习是我们自己与生俱来的能力我们总是想要去拥有些什么,然后就会不由自主地去选择学习所有说,我们不能因为一些其他的事情而把自己的心态给坏了保持一个良好的心态是我们能够成功的保证永远永远永远要端正好自己的态度切记不可半途而废,要做就一定要做到自己所能做到的最好!!!树立自己的目标曾经很多次,我自己问过我自己,到底想要获得什么,亦或是成为什么样的人也是每一次,都没有一个准确的回复,可能还是不能够很好地定位自己吧给自己一个定位,的却是一件不容易的事情毕竟每个人的人生都有无限个可能,想走什么样的路,成就什么样的人生这只能由我们自己去决定可能我们会为了某一件事而冲动,亦或是感触良多,从而自发的有了树立目标的冲动也许这就是我们以后要走的路了,是啊~每一个人都不容易为什么学算法?今天趁着自己有目标的时候给自己点明方向(我,为何要学习算法?)学算法的好处算法可以帮助人们思考,使得自己的大脑能够一直保持思考的状态,对自己的思维的提升很重要学习算法也是为自己开辟另外一条路,为自己以后能够多一些打算算法也能够很好地帮助我们学习解决一个问题的思路算法所能够带来的东西能够更好地帮助我们理解计算机的运行原理和内部结构人们都说算法难,学着无聊,很没意思就是因为枯燥无味,所以算法工程师才显得重要计算机专业是一个应该处于持续思考的专业,是要动脑子的 专业算法可以帮助我们很多,总之,学算法对我们自身没有坏处(除了掉头发厉害0.0)留给自己的话每个人都是在这个世界上第一次的活着那么为什么不好好的为了自己活一次是的,我们不知道结局或是怎样,我们只是为了自己的喜欢而选择去怎么样的生活也许我们可能会在这条路上不断地抱怨,不自觉的去和别人对比,但是我只是想给自己说一句话就算对比了,我能得到什么??是失望亦或是开心??但是这些没有用呀!!为什么不好好的活在当下,喜欢什么就去做什么~是啊,我们现在是没有什么能力,但是我们年轻呀,这就是我们最大的资本千万不要比人说什么你就信什么,还是那句话,生而为人,都是第一次别人又有什么能力对你指手画脚的呢?为了自己,好好地活过每一天……放慢脚步,去领略这个世界的美丽……面对自己,活出人生的意义……]]></content>
<categories>
<category>总结</category>
<category>想法</category>
</categories>
<tags>
<tag>想法</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day8]]></title>
<url>%2F2019%2F07%2F25%2FDay8%2F</url>
<content type="text"><![CDATA[Day8今天学习了 树的直径树的直径->双重BFS/DFS跑图学的效果整体还行树什么是树?树(tree)是包含n(n>0)个结点的有穷集,其中:每个元素称为结点(node);有一个特定的结点被称为根结点或树根(root);除根结点之外的其余数据元素被分为m(m≥0)个互不相交的集合T1,T2,…Tm−1,其中每一个集合Tm−1(1≤i≤m)本身也是一棵树,被称作原树的子树(subtree)。树的直径的定义树中距离最大的两个结点之间的距离称为树的直径。求解方法两次dfs或bfs。第一次任意选一个点进行dfs(bfs)找到离它最远的点,此点就是最长路的一个端点,再以此点进行dfs(bfs),找到离它最远的点,此点就是最长路的另一个端点,于是就找到了树的直径。证明假设此树的最长路径是从s到t,我们选择的点为u。反证法:假设搜到的点是v。1、v在这条最长路径上,那么dis[u,v]>dis[u,v]+dis[v,s],显然矛盾。2、v不在这条最长路径上,我们在最长路径上选择一个点为po,则dis[u,v]>dis[u,po]+dis[po,t],那么有dis[s,v]=dis[s,po]+dis[po,u]+dis[u,v]>dis[s,po]+dis[po,t]=dis[s,t],即dis[s,v]>dis[s,t],矛盾。也许你想说u本身就在最长路径,或则其它的一些情况,但其实都能用类似于上面的反证法来证明的。综上所述,你两次dfs(bfs)就可以求出最长路径的两个端点和路径长度相关题目POJ 2631POJ 1985POJ 1383带权图相关代码模板(用的时候要合理变动)1234567891011121314151617181920212223242526272829303132333435363738394041424344454647# include <iostream># include <cstring># include <queue># include <vector>const int maxn =100020;using namespace std ;int dis[maxn], ans ;bool vis[maxn];vector<pair<int ,int> > V[maxn];int bfs(int x){ memset(dis ,0 , sizeof(dis)); memset(vis ,0 , sizeof(vis)); queue<int > Q ; Q.push(x); vis[x]=1; int point=0; while (!Q.empty()){ int F = Q.front(); Q.pop(); if(dis[F] > ans ){ ans = dis[F]; point = F; } pair <int ,int > t ; for (int i =0; i < V [F].size (); i ++){ t = V[F][i]; if(vis[t.first]==0){ vis[t.first]=1; dis[t.first]=dis[F] + t.second ; Q.push (t.first); } } } return point;}int main(){ int x,y,z ; 输入 ans=0; int point=bfs(1); ans=0; bfs(point); cout<<ans<<endl ; return 0;}OJ链接:https://vjudge.net/contest/313488#overviewLabyrinthProblem DescriptionThe northern part of the Pyramid contains a very large and complicated labyrinth. The labyrinth is divided into square blocks, each of them either filled by rock, or free. There is also a little hook on the floor in the center of every free block. The ACM have found that two of the hooks must be connected by a rope that runs through the hooks in every block on the path between the connected ones. When the rope is fastened, a secret door opens. The problem is that we do not know which hooks to connect. That means also that the neccessary length of the rope is unknown. Your task is to determine the maximum length of the rope we could need for a given labyrinth.InputThe input consists of T test cases. The number of them (T) is given on the first line of the input file. Each test case begins with a line containing two integers C and R (3 <= C,R <= 1000) indicating the number of columns and rows. Then exactly R lines follow, each containing C characters. These characters specify the labyrinth. Each of them is either a hash mark (#) or a period (.). Hash marks represent rocks, periods are free blocks. It is possible to walk between neighbouring blocks only, where neighbouring blocks are blocks sharing a common side. We cannot walk diagonally and we cannot step out of the labyrinth.The labyrinth is designed in such a way that there is exactly one path between any two free blocks. Consequently, if we find the proper hooks to connect, it is easy to find the right path connecting them.OutputYour program must print exactly one line of output for each test case. The line must contain the sentence “Maximum rope length is X.” where Xis the length of the longest path between any two free blocks, measured in blocks.12345678910111213141516171819Sample Input23 3####.####7 6########.#.####.#.####.#.#.##.....########Sample OutputMaximum rope length is 0.Maximum rope length is 8.HintHuge input, scanf is recommended.If you use recursion, maybe stack overflow. and now C++/c 's stack size is larger than G++/gcccode:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<queue>using namespace std;const int mod = 1e9;typedef long long ll;int n, m;char a[2000][3000];int dis[2000][2000];int ans;int d[4][2] = { 1, 0, -1, 0, 0, 1, 0, -1};struct node{ int x, y;}first, second;void bfs(node first){ ans = 0; memset(dis, -1, sizeof dis); queue<node> q; node e1, e2; e1.x = first.x, e1.y = first.y, dis[e1.x][e1.y] = 0; q.push(e1); while(!q.empty()) { e1 = q.front(); q.pop(); for(int i = 0; i < 4; i ++) { e2.x = e1.x + d[i][0]; e2.y = e1.y + d[i][1]; if(e2.x >= 0 && e2.y >= 0 && e2.x < n && e2.y < m && a[e2.x][e2.y] != '#' && dis[e2.x][e2.y] == -1) { q.push(e2); dis[e2.x][e2.y] = dis[e1.x][e1.y] + 1; if(ans < dis[e2.x][e2.y]) { ans = dis[e2.x][e2.y]; second.x = e2.x; second.y = e2.y; } } } }}int main(){ int T; cin >> T; while(T --) { cin >> m >> n; for(int i = 0; i < n; i ++) { scanf("%s",&a[i]); } for(int i = 0; i < n; i ++) { for(int j = 0; j < m; j ++) { if(a[i][j] == '.') { first.x = i; first.y = j; } } } bfs(first); bfs(second); printf("Maximum rope length is %d.\n",ans); } return 0;}Cow MarathonProblem DescriptionAfter hearing about the epidemic of obesity in the USA, Farmer John wants his cows to get more exercise, so he has committed to create a bovine marathon for his cows to run. The marathon route will include a pair of farms and a path comprised of a sequence of roads between them. Since FJ wants the cows to get as much exercise as possible he wants to find the two farms on his map that are the farthest apart from each other (distance being measured in terms of total length of road on the path between the two farms). Help him determine the distances between this farthest pair of farms.有n个农田和m条路,以及每条路的方向(方向在这道题中没有用),求最长的一条路,也就是两点间的最大距离,即树的直径.InputLines 1…..: Same input format as “Navigation Nightmare”.OutputLine 1: An integer giving the distance between the farthest pair of farms.123456789101112Sample Input7 61 6 13 E6 3 9 E3 5 7 S4 1 3 N2 4 20 W4 7 2 SSample Output52HintThe longest marathon runs from farm 2 via roads 4, 1, 6 and 3 to farm 5 and is of length 20+3+13+9+7=52.code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364#include<iostream>#include<cstring>#include<cstdio>#include<queue>#include<vector>const int maxn = 5e5 + 10;//数组不要太大,不然会超时using namespace std;int dis[maxn];int ans, en;bool vis[maxn];vector <pair<int,int> >V[maxn];int bfs(int x){ ans = 0; memset(dis,0,sizeof(dis)); memset(vis,0,sizeof(vis)); queue<int> q; q.push(x); vis[x]=1; en = 0; while(!q.empty()) { int f = q.front(); q.pop(); if(dis[f] > ans) { ans = dis[f]; en = f; } pair<int,int > t; for(int i = 0; i < V[f].size();i ++) { t = V[f][i]; if(vis[t.first] == 0) { vis[t.first] = 1; dis[t.first] = dis[f] + t.second; q.push(t.first); } } } return en;}int main (){ int x, y, z; char c[100]; int n, m; while(~scanf("%d %d",&m,&n)) { for(int i = 0;i < n; i ++) V[i].clear();//注意每次用完vector之后要清空 for(int i = 0; i < n; i ++) { scanf("%d %d %d %s",&x,&y,&z,&c); V[x].push_back(make_pair(y,z)); V[y].push_back(make_pair(x,z)); } bfs(1); bfs(en); cout << ans << endl; } return 0;}Roads in the NorthProblem DescriptionBuilding and maintaining roads among communities in the far North is an expensive business. With this in mind, the roads are build such that there is only one route from a village to a village that does not pass through some other village twice.Given is an area in the far North comprising a number of villages and roads among them such that any village can be reached by road from any other village. Your job is to find the road distance between the two most remote villages in the area.The area has up to 10,000 villages connected by road segments. The villages are numbered from 1.InputInput to the problem is a sequence of lines, each containing three positive integers: the number of a village, the number of a different village, and the length of the road segment connecting the villages in kilometers. All road segments are two-way.OutputYou are to output a single integer: the road distance between the two most remote villages in the area.12345678Sample Input5 1 61 4 56 3 92 6 86 1 7Sample Output22code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081#include<iostream>#include<algorithm>#include<cstring>#include<cmath>#include<queue>#include<vector>using namespace std;const int mod = 1e9;const int maxx = 1e5 + 10;typedef long long ll;vector<pair<int, int> >v[maxx];int ans;bool vis[maxx];int dis[maxx];int en; //不要用end,是一个保留字int bfs(int x){ //每次bfs都要初始化 ans = 0; memset(vis, 0, sizeof vis); memset(dis, 0, sizeof dis); //套用bfs模板 queue<int> q; vis[x] = 1; q.push(x); en = 0; while(!q.empty()) { int f = q.front(); q.pop(); //随着ans的不断更新,直到找到一个端点,标记下来 if(dis[f] > ans) { ans = dis[f]; en = f;//一段的开始 } //创建新的数对,表示的是与v[]相连的点 pair<int , int> p; //遍历所有地点 ,根据距离,寻找一端的点 for(int i = 0; i < v[f].size(); i ++) { p = v[f][i];//表示 寻找这个点在图中的所有可能 if(vis[p.first] == 0) //如果这个地点没有经过 { vis[p.first] = 1;//先标记 dis[p.first] = dis[f] + p.second;//加上距离 ,更新ans q.push(p.first);//入队,寻找这个点的所有可能性 } } } return en;//将一端的标记返回出去}int main(){ int x, y, z; while(~scanf("%d %d %d",&x, &y, &z)) { //存图,意思就是将与x,y相连的点和对应的权值存储起来,因为是双向的,所以权值一样 v[x].push_back(make_pair(y, z)); v[y].push_back(make_pair(x, z)); } //第一次bfs随便找个点去找到整个图的一个端点 bfs(1); //第二次bfs从一个端点出发去找另一个端点,即为树的直径 bfs(en); //输出答案ans cout << ans << endl; return 0;}/*题意:有10000个村庄,有很多条路,现在这些路已经把村庄都连了起来,求最远的两个村庄的路的距离。思路,把每一边都历遍一下,找到两个距离最远的村庄。这里有一个结论,在图中,要找到距离最远的两点,先随便从一个点入手BFS,找到距离这个点最远的点,在从这个点BFS找到距离这点最远的点,这两点之间的距离就是这棵树的直径。所以直接进行BFS搜索就行了。*/ComputerProblem DescriptionA school bought the first computer some time ago(so this computer’s id is 1). During the recent years the school bought N-1 new computers. Each new computer was connected to one of settled earlier. Managers of school are anxious about slow functioning of the net and want to know the maximum distance Si for which i-th computer needs to send signal (i.e. length of cable to the most distant computer). You need to provide this information.Hint: the example input is corresponding to this graph. And from the graph, you can see that the computer 4 is farthest one from 1, so S1 = 3. Computer 4 and 5 are the farthest ones from 2, so S2 = 2. Computer 5 is the farthest one from 3, so S3 = 3. we also get S4 = 4, S5 = 4.Input输入文件包含多组测试样例。在每组样例中,第一行中都有自然数n(n<=10000),然后是(n-1)行,其中包含对计算机的描述。第i行包含两个自然数-第i计算机所连接的计算机和用于连接的电缆长度。电缆总长度不超过10^9。输入行中的数字用空格分隔。Output对于每组样例,输出n行。第i行第i台计算机的到其他计算机的最大长度Si(1<=i<=n)。1234567891011121314Sample Input51 12 13 11 1Sample Output32344提示示例输入与此图对应。从图中,你可以看到计算机4离1最远,所以s1=3。计算机4和5是距离2最远的,所以s2=2。计算机5是离3最远的,所以s3=3。我们也得到了s4=4,s5=4。code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475#include<iostream>#include<algorithm>#include<cstring>#include<cmath>#include<queue>#include<vector>using namespace std;const int mod = 1e9;const int maxx = 1e5 + 10;typedef long long ll;vector<pair<int, int> > v[maxx];bool vis[maxx];int dis[maxx];int diss[maxx];int ans;int bfs(int x){ ans = 0; memset(vis, 0, sizeof vis); memset(dis, 0, sizeof dis); queue<int> q; q.push(x); vis[x] = 1; int point; while(!q.empty()) { int f = q.front(); q.pop(); if(ans < dis[f]) { ans = dis[f]; point = f; } for(int i = 0; i < v[f].size(); i ++) { if(vis[v[f][i].first] == 0) { vis[v[f][i].first] = 1; dis[v[f][i].first] = v[f][i].second + dis[f]; q.push(v[f][i].first); } } } return point;}int main(){ int n; int a, b; while(~scanf("%d",&n)) { for(int i = 0; i <= n; i ++) v[i].clear(); for(int i = 1; i < n; i ++) { cin >> a >> b; v[i + 1].push_back(make_pair(a, b)); v[a].push_back(make_pair(i + 1, b)); } int point; point = bfs(bfs(1)); for(int i = 1; i <= n; i ++) diss[i] = dis[i]; bfs(point); for(int i = 1; i <= n; i ++) { cout << max(dis[i], diss[i]) << endl; } } return 0;}Farthest Nodes in a TreeProblem DescriptionGiven a tree (a connected graph with no cycles), you have to find the farthest nodes in the tree. The edges of the tree are weighted and undirected. That means you have to find two nodes in the tree whose distance is maximum amongst all nodes.InputInput starts with an integer T (≤ 10), denoting the number of test cases.Each case starts with an integer n (2 ≤ n ≤ 30000) denoting the total number of nodes in the tree. The nodes are numbered from 0 to n-1. Each of the next n-1 lines will contain three integers u v w (0 ≤ u, v < n, u ≠ v, 1 ≤ w ≤ 10000) denoting that node u and v are connected by an edge whose weight is w. You can assume that the input will form a valid tree.OutputFor each case, print the case number and the maximum distance.1234567891011121314Sample Input240 1 201 2 302 3 5050 2 202 1 100 3 290 4 50Sample OutputCase 1: 100Case 2: 80code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667//e#include<iostream>#include<cstring>#include<cstdio>#include<queue>#include<vector>const int maxn = 5e5 + 10;using namespace std;int dis[maxn];int ans, en;bool vis[maxn];vector <pair<int,int> >V[maxn];int bfs(int x){ ans = 0; memset(dis,0,sizeof(dis)); memset(vis,0,sizeof(vis)); queue<int>q; q.push(x); vis[x]=1; en = 0; while(!q.empty()) { int f = q.front(); q.pop(); if(dis[f] > ans) { ans = dis[f]; en = f; } pair<int,int > t; for(int i = 0; i < V[f].size();i ++) { t = V[f][i]; if(vis[t.first] == 0) { vis[t.first] = 1; dis[t.first] = dis[f] + t.second; q.push(t.first); } } } return en;}int main (){ int x, y, z; int T, n; cin >> T; int k = 1; while(T --) { cin >> n; for(int i = 0;i < n; i ++) V[i].clear();//注意每次用完vector之后要清空 for(int i = 0; i < n - 1; i ++) { scanf("%d %d %d",&x,&y,&z); V[x].push_back(make_pair(y,z)); V[y].push_back(make_pair(x,z)); } bfs(0); bfs(en); printf("Case %d: %d\n",k ++, ans); } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
<tag>图论</tag>
<tag>搜素算法</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day7]]></title>
<url>%2F2019%2F07%2F24%2FDay7%2F</url>
<content type="text"><![CDATA[Day7今天学习的是dfs常规操作~~~~没写完题这次不是debug了,是真的不会(太菜了。。。)未完待续链接:https://vjudge.net/contest/313683#overviewOil DepositsProblem DescriptionThe GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSurvComp works with one large rectangular region of land at a time, and creates a grid that divides the land into numerous square plots. It then analyzes each plot separately, using sensing equipment to determine whether or not the plot contains oil. A plot containing oil is called a pocket. If two pockets are adjacent, then they are part of the same oil deposit. Oil deposits can be quite large and may contain numerous pockets. Your job is to determine how many different oil deposits are contained in a grid.InputThe input file contains one or more grids. Each grid begins with a line containing m and n, the number of rows and columns in the grid, separated by a single space. If m = 0 it signals the end of the input; otherwise 1 <= m <= 100 and 1 <= n <= 100. Following this are m lines of n characters each (not counting the end-of-line characters). Each character corresponds to one plot, and is either *', representing the absence of oil, or@’, representing an oil pocket.OutputFor each grid, output the number of distinct oil deposits. Two different pockets are part of the same oil deposit if they are adjacent horizontally, vertically, or diagonally. An oil deposit will not contain more than 100 pockets.123456789101112131415161718192021Sample Input1 1*3 5*@*@***@***@*@*1 8@@****@*5 5****@*@@*@*@**@@@@*@@@**@0 0Sample Output0122code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869//板子题,8个方向#include<bits/stdc++.h>using namespace std;const int mod = 101;char a[mod][mod];int vis[mod][mod];int ans;int n, m;int d[8][2] = { -1, 1, -1, 0, -1, -1, 0, 1, 0, -1, 1, 1, 1, 0, 1, -1};void DFS(int x, int y){ if(x < 0 || y < 0 || x >=n || y >= m) return ; int xx, yy;// vis[x][y] = 1; for(int i = 0; i < 8; i ++) { xx = x + d[i][0]; yy = y + d[i][1]; if(xx >= 0 && yy >= 0 && xx < n && yy < m && a[xx][yy] != '*') { a[xx][yy] = '*'; DFS(xx, yy); } }}int main(){ int sx, sy; while(~scanf("%d %d",&n, &m) && n) {// memset(vis, 0, sizeof(vis)); ans = 0; for(int i = 0; i < n; i ++) { for(int j = 0; j < m; j ++) { cin >> a[i][j]; } } for(int i = 0; i < n; i ++) { for(int j = 0; j < m; j ++) { if(a[i][j] == '@') { ans ++; DFS(i, j); } } } cout << ans << endl; } return 0;}How Many Equations Can You FindProblem DescriptionNow give you an string which only contains 0, 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9.You are asked to add the sign ‘+’ or ’-’ between the characters. Just like give you a string “12345”, you can work out a string “123+4-5”. Now give you an integer N, please tell me how many ways can you find to make the result of the string equal to N .You can only choose at most one sign between two adjacent characters.InputEach case contains a string s and a number N . You may be sure the length of the string will not exceed 12 and the absolute value of N will not exceed 999999999999.OutputThe output contains one line for each data set : the number of ways you can find to make the equation.123456Sample Input123456789 321 1Sample Output181code:1234567891011121314151617181920212223242526272829303132333435//每一位都可能放或者不放算术符#include<bits/stdc++.h>typedef long long ll;using namespace std;const int MAXN = 200 + 10;char str[MAXN][MAXN];bool vis[MAXN][MAXN];char s[100100];ll n,m,len;ll ans;void DFS(int sum,int m){ if(m==len){ if(sum==n){ ans++; } return ; } ll mm=0; for(int i=m;i<len;i++){ mm=mm*10+(s[i]-'0'); DFS(sum+mm,i+1); if(m!=0){ DFS(sum-mm,i+1); } }}int main(){ while(scanf("%s%lld",s,&n)!=EOF){ ans=0; len=strlen(s); DFS(0,0); printf("%d\n",ans); } return 0;}N皇后问题Problem Description在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。你的任务是,对于给定的N,求出有多少种合法的放置方法。Input共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。Output共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。123456789Sample Input1850Sample Output19210code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137//第一种写法#include<bits/stdc++.h>using namespace std;int vis[3][20], p[20]; // vis用来存储↖↑↗在此三个方向都不能有皇后 p[n]用来存储解int n;int num;void DFS(int row){ int i; if(row == n + 1) //已经够n行了 { num ++; return ; } for(i = 1; i <= n; i ++) { if(vis[0][row - i + n] == 0 && vis[1][i] == 0 && vis[2][row + i] == 0) { vis[0][row - i + n] = vis[1][i] = vis[2][row + i] = 1;//变值 DFS(row + 1); vis[0][row - i + n] = vis[1][i] = vis[2][row + i] = 0;//回溯 } } }int main(){ for(n = 1; n <= 10; n ++) //打表防超时 { memset(vis, 0, sizeof(vis)); num = 0; DFS(1); p[n] = num; } while(~scanf("%d",&n) && n) { cout << p[n] << endl; } return 0;}//第二种#include<bits/stdc++.h>using namespace std;const int N = 12;int a[N], cnt;//x,i表示行,y,a[i]表示列,用check来表示是否可以放置bool check(int x, int y){ for(int i = 1; i < x; i ++) { //abs(x - i) == abs(a[i] - y)表示的是(x-i)/(a[i]-y)的斜率的绝对值是否为1 if(a[i] == y || abs(x - i) == abs(a[i] - y)) return false; } return true;}void DFS(int x, int m){ //x越界的时候,同时也表示到底了,回溯 if(x > m) { cnt ++; return ; } for(int i = 1; i <= m; i ++) { if(check(x, i)) { a[x] = i; DFS(x + 1, m); } } return ;}int main(){ //ans用来存放数据,不打表的话可能超时 int i, ans[11]; //打表并深搜 for(int i = 1; i < 11; i ++) { cnt = 0; DFS(1, i); ans[i] = cnt; } while(cin >> i) { if(i == 0) return 0; cout << ans[i] << endl; }}//第三种//行,列,两个对角,共四个数组,每次存入都要查看是否已经存放过#include<bits/stdc++.h>using namespace std;typedef long long ll;const int INF=0x3f3f3f3f;int a[105],b[105],c[105],d[105];//a:行,b:列,c:左下到右上,d:左上到右下int i,ans=0;void DFS(int x){ if(x==i+1){ ans++; } for(int j=1;j<=i;j++){ if(!b[j]&&!c[j+x]&&!d[x-j+i]){ a[x]=j; b[j]=1; c[j+x]=1; d[x-j+i]=1; DFS(x+1); b[j]=0; c[j+x]=0; d[x-j+i]=0; } }}int main(){ int num[15]; int n; for(i=1;i<11;i++) { ans=0; DFS(1); num[i]=ans; } while(cin>>n&&n) { cout<<num[n]<<endl; } return 0;}Fox And Two DotsProblem DescriptionFox Ciel is playing a mobile puzzle game called “Two Dots”. The basic levels are played on a board of size n × m cells, like this:Each cell contains a dot that has some color. We will use different uppercase Latin characters to express different colors.The key of this game is to find a cycle that contain dots of same color. Consider 4 blue dots on the picture forming a circle as an example. Formally, we call a sequence of dots d1, d2, …, dk a cycle if and only if it meets the following condition:These k dots are different: if i ≠ j then di is different from dj.k is at least 4.All dots belong to the same color.For all 1 ≤ i ≤ k - 1: di and di + 1 are adjacent. Also, dk and d1 should also be adjacent. Cells x and y are called adjacent if they share an edge.Determine if there exists a cycle on the field.InputThe first line contains two integers n and m (2 ≤ n, m ≤ 50): the number of rows and columns of the board.Then n lines follow, each line contains a string consisting of m characters, expressing colors of dots in each line. Each character is an uppercase Latin letter.OutputOutput “Yes” if there exists a cycle, and “No” otherwise.1234567891011121314151617181920212223242526272829303132333435363738394041424344ExamplesInput3 4AAAAABCAAAAAOutputYesInput3 4AAAAABCAAADAOutputNoInput4 4YYYRBYBYBBBYBBBYOutputYesInput7 6AAAAABABBBABABAAABABABBBABAAABABBBABAAAAABOutputYesInput2 13ABCDEFGHIJKLMNOPQRSTUVWXYZOutputNoNoteIn first sample test all 'A' form a cycle.In second sample there is no such cycle.The third sample is displayed on the picture above ('Y' = Yellow, 'B' = Blue, 'R' = Red).code:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465//d#include<iostream>#include<cstring>using namespace std;int vis[55][55];char a[55][55];int d[4][2] = { -1, 0, 1, 0, 0, 1, 0, -1};int n, m, k;//四个变量表示当前坐标点和上一个坐标点void DFS(int x, int y, int cx, int cy){ if(vis[x][y] == 1) { //想要表示成环,只需要走以前走过的点就行了,也就是走到了标记过的点 k = 1; //表示成环 return; } vis[x][y] = 1; int xx, yy; for(int i = 0; i < 4; i ++) { xx = x + d[i][0]; yy = y + d[i][1]; // 表示不能往回走并且不能越界 if(xx >= 0 && yy >= 0 && xx < n && yy < m && a[xx][yy] == a[x][y] && (xx != cx || yy != cy)) { DFS(xx, yy , x, y); } }}int main(){ while(~scanf("%d %d",&n, &m)) { k = 0; memset(vis, 0, sizeof(vis)); for(int i = 0; i < n; i ++) { scanf("%s",&a[i]); } for(int i = 0; i < n; i ++) { for(int j = 0; j < m; j ++) { //全部遍历,找寻可能点 if(vis[i][j] == 1) continue; DFS(i, j, i, j); //找到了点,退出循环 if(k == 1) break; } if(k == 1) break; } if(k == 1) puts("Yes"); else puts("No"); } return 0;}棋盘问题Problem Description在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。Input输入含有多组测试数据。每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n当为-1 -1时表示输入结束。随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。Output对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。12345678910111213Sample Input2 1#..#4 4...#..#..#..#...-1 -1Sample Output21code:12345678910111213141516171819202122232425262728293031323334353637383940#include<cstdio>#include<iostream>#include<cstring>#include<queue>using namespace std;typedef long long ll;const int MAXN = 200 + 10;char str[MAXN][MAXN];bool vis[MAXN];int n,k;ll ans;int d[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};void DFS(int x,int num){ if(num==k){ ans++; return; } for(int i=x;i<n;i++){ for(int j=0;j<n;j++){ if(str[i][j]=='#'&&!vis[j]){ vis[j]=true; DFS(i+1,num+1); vis[j]=false; } } }}main(){ while(scanf("%d%d",&n,&k)!=EOF&&n!=-1&&k!=-1){ memset(str,0,sizeof(str)); memset(vis,false,sizeof(vis)); ans=0; for(int i=0;i<n;i++){ scanf("%s",str[i]); } DFS(0,0); printf("%lld\n",ans); } return 0;}SudokuProblem DescriptionSudoku is a very simple task. A square table with 9 rows and 9 columns is divided to 9 smaller squares 3x3 as shown on the Figure. In some of the cells are written decimal digits from 1 to 9. The other cells are empty. The goal is to fill the empty cells with decimal digits from 1 to 9, one digit per cell, in such way that in each row, in each column and in each marked 3x3 subsquare, all the digits from 1 to 9 to appear. Write a program to solve a given Sudoku-task.InputThe input data will start with the number of the test cases. For each test case, 9 lines follow, corresponding to the rows of the table. On each line a string of exactly 9 decimal digits is given, corresponding to the cells in this line. If a cell is empty it is represented by 0.OutputFor each test case your program should print the solution in the same format as the input data. The empty cells have to be filled according to the rules. If solutions is not unique, then the program may print any one of them.123456789101112131415161718192021Sample Input1103000509002109400000704000300502006060000050700803004000401000009205800804000107Sample Output143628579572139468986754231391542786468917352725863914237481695619275843854396127code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576//每个为0的格子都可能放1~9放完后再查看每一行,列,每个小九宫格中是否含有这个数,如果没有则继续DFS下个格子#include<iostream>#include<cstdio>using namespace std;typedef long long ll;int a[10][10];int check(int n,int num){ for(int i=0;i<9;i++) { int j=n%9; if(a[i][j]==num) return 0; } for(int j=0;j<9;j++) { int i=n/9; if(a[i][j]==num) return 0; } int ii=n/9/3*3; int jj=n%9/3*3; for(int i=ii;i<ii+3;i++) for(int j=jj;j<jj+3;j++) { if(a[i][j]==num) return 0; } return 1;}int temp;int DFS(int n){ if(n>=81) { temp=1; return 0; } if(a[n/9][n%9]!=0) DFS(n+1); else { for(int i=1;i<=9;i++) { if(check(n,i)==1) { a[n/9][n%9]=i; DFS(n+1); if(temp==1) return 0; a[n/9][n%9]=0; } } }}int main(){ int T; scanf("%d",&T); while(T--) { temp=0; for(int i=0;i<9;i++) for(int j=0;j<9;j++) scanf("%1d",&a[i][j]); DFS(0); for(int i=0;i<9;i++) { for(int j=0;j<9;j++) printf("%d",a[i][j]); printf("\n"); } } return 0;}放苹果Problem Description把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。Input第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。Output对输入的每组数据M和N,用一行输出相应的K。12345Sample Input17 3Sample Output8code:12345678910111213141516171819202122232425262728293031323334353637383940#include<iostream>//#include<>using namespace std;int n, m;int solve(int m, int n){ if(m == 0 || n == 1) return 1; if(n > m) return solve(m, m); else { return solve(m, n - 1) + solve(m - n, n); }}int main(){ int t; cin >> t; while(t --) { cin >> m >> n; int ans = solve(m, n); cout << ans << endl; } return 0;}//PS:苹果可以为0, 盘子不能为0(毕竟是放苹果)/*分析:如果盘子比苹果多,那么一定会有盘子是空的,即为 solve(m, m);那么这就是一种情况如果盘子比苹果少,那么可以分为:1. 假设没有空盘子,那么上面都有苹果,那么可以看成一开始每个盘子上都有一个苹果 然后我们每次加一个苹果,就剩下m - n个苹果,直到放完为止 即为 solve(m - n, n)2. 假设有空盘子,那么每次拿走一个空盘子 即为: solve(m, n - 1);结果即为这两种情况的和*/Tempter of the BoneProblem Description小明做了一个很久很久的梦,醒来后他竟发现自己和朋友在一个摇摇欲坠的大棋盘上,他们必须得想尽一切办法逃离这里。经过长时间的打探,小明发现,自己所在的棋盘格子上有个机关,上面写着“你只有一次机会,出发后t秒大门会为你敞开”,而他自己所在的棋盘是大小为 N*M 的长方形,他可以向上下左右四个方向移动(不可走有障碍点)。棋盘中有一扇门。根据机关的提示,小明顿时明白了,他和朋友必须在第 t 秒到门口。而这一切,没有回头路!因为一旦他移动了,他刚才所在的点就会消失,并且他不能在一个点上停留超过一秒,不然格子会爆炸。大逃亡开始了,请问小明和朋友能安全的逃出这奇怪的棋盘吗?Input输入多组测试数据。每个测试用例的第一行包含三个整数 N、M 和 T ( 1 < N , M < 7 ; 0 < T < 50 ),分别表示棋盘的大小和门打开的时间。接下来的N行给出棋盘布局,每一行包含M个字符。其中“.”: 无障碍点“X”: 障碍点“S”: 起点“D”: 门输入以 3 个 0 结束。这个测试用例不需要处理。输入数据中的空格有些问题,请不要使用getchar(),如果一定要用可以选择scanf(“%s”,) 自动忽略空格Output对于每组样例输出一行。如果小明能够安全逃出,输出 “YES” ,否则输出 “NO”。1234567891011121314Sample Input4 4 5S.X...X...XD....3 4 5S.X...X....D0 0 0Sample OutputNOYEScode:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111#include<bits/stdc++.h>using namespace std;int n, m, t;char a[30][30];int vis[40][40];int d[4][2] = { -1, 0, 1, 0, 0, 1, 0, -1};int flag;int ex, ey;void DFS(int sx, int sy, int ans){ int xx, yy; //很重要,可以减少步骤,也是如何使一旦找到需要的路线就可以连续return出 if(flag) return; if(sx == ex && sy == ey && ans == t) { flag = 1; return; } //剪枝的核心 int tem = t - ans - abs(ex - sx) - abs(ey - sy); //剪枝:如果剩余的步数已经不足以走到出口,且必须是偶数,偶数-偶数=偶数,奇数-奇数=偶数, if(tem < 0 || tem & 1) return; for(int i = 0; i < 4; i ++) { xx = sx + d[i][0]; yy = sy + d[i][1]; if(xx >= 0 && yy >= 0 && xx < n && yy < m && vis[xx][yy] == 0 && a[xx][yy] != 'X') { vis[xx][yy] = 1; DFS(xx, yy, ans + 1); if(flag) return; vis[xx][yy] = 0; } } return;}int main(){ int wall, sx, sy; while(~scanf("%d %d %d",&n, &m, &t)) { flag = 0, wall = 0; if(n == 0 && m == 0 && t == 0) break; memset(vis, 0, sizeof(vis)); for(int i = 0; i < n; i ++) { for(int j = 0; j < m; j ++) { cin >> a[i][j]; if(a[i][j] == 'S') { sx = i; sy = j; } if(a[i][j] == 'D') { ex = i; ey = j; } if(a[i][j] == 'X') { wall ++; } } } if(t > n * m - wall - 1) { puts("NO"); continue; } vis[sx][sy] = 1; DFS(sx, sy, 0); if(flag) puts("YES"); else puts("NO"); } return 0;}/*关于奇偶剪枝:不利用奇偶剪枝的话一直TLE,现在对于奇偶剪枝不理解,暂时记住公式,t-cnt为目前剩余的时间,abs(x-dx)+abs(y-dy)为从当前改点到终点(门)所需要的最短步数,剩余时间为偶数(奇数),就需要走偶数步(奇数步),奇数-偶数 = 奇数而奇数-奇数= 偶数,偶数-偶数=偶数所以只有当剩余的时间与目前位置到终点的最短步数奇偶性相同时,才有可能恰好在t时刻到大门的地方(因为中间会有墙,需根据题目条件继续判定,奇偶剪枝只是把范围缩小了)还有就是开头时间步数可移动位置的数量关系,也属于剪枝 勿忘abs(x-dx)+abs(y-dy)为从当前改点到终点(门)所需要的最短步数,但他会根据总时间的需要进行绕行,奇数步绕行后也是奇数步,偶数步绕行后也是偶数步,故他们之间奇偶性是相同的2.此题一开始还有个纠结的问题,就是深搜如何搜到符合条件的路径后就直接退出,一开始不知道怎么解决,因为觉得深搜利用了递归,无法return一下,就直接结束,此时用一个ans来解决就OK了,当搜索多条路径时,记得要还原需要在可能有变化找到结果标志flag及时return,3.对于下一步要走的路径(1)先确定下一步要走哪个格 用for函数和方向数组(2)通过book标记数组和map地图数组判断这个位置是否可以走(越界·是否是墙,是否已经测试或者走过)(3)标记这个位置已经走过(4)进入下一位置,传入这一数组(4)将以标记的数组撤回,以便下次再次搜索(6)将改变的值再改回来4.注意数组变量是否混合,每一个数组或者变量名是否改变5,记得初始化,尤其是while函数*/Red and BlackProblem DescriptionThere is a rectangular room, covered with square tiles. Each tile is colored either red or black. A man is standing on a black tile. From a tile, he can move to one of four adjacent tiles. But he can’t move on red tiles, he can move only on black tiles.Write a program to count the number of black tiles which he can reach by repeating the moves described above.InputThe input consists of multiple data sets. A data set starts with a line containing two positive integers W and H; W and H are the numbers of tiles in the x- and y- directions, respectively. W and H are not more than 20.There are H more lines in the data set, each of which includes W characters. Each character represents the color of a tile as follows.‘.’ - a black tile‘#’ - a red tile‘@’ - a man on a black tile(appears exactly once in a data set)OutputFor each data set, your program should output a line which contains the number of tiles he can reach from the initial tile (including itself).123456789101112131415161718192021222324252627282930313233343536373839404142Sample Input6 9....#......#..............................#@...#.#..#.11 9.#..........#.#######..#.#.....#..#.#.###.#..#.#..@#.#..#.#####.#..#.......#..#########............11 6..#..#..#....#..#..#....#..#..###..#..#..#@...#..#..#....#..#..#..7 7..#.#....#.#..###.###...@...###.###..#.#....#.#..0 0Sample Output4559613code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657#include<bits/stdc++.h>using namespace std;char a[30][30];int vis[30][30];int m, n;int ans;int d[4][2] = { 0, 1, 0, -1, 1, 0, -1, 0};void DFS(int x, int y){ int xx, yy; vis[x][y] = 1; if(x < 0 || y < 0 || x >= n || y >= m) return ; for(int i = 0; i < 4; i ++) { xx = x + d[i][0]; yy = y + d[i][1]; if(xx >= 0 && yy >= 0 && xx < n && yy < m && vis[xx][yy] == 0 && a[xx][yy] != '#') { ans ++; DFS(xx, yy); } }}int main(){ int sx, sy; while(~scanf("%d %d",&m, &n)) { if(m == 0 && n == 0) break; memset(vis, 0, sizeof(vis)); ans = 1; for(int i = 0; i < n; i ++) { for(int j = 0; j < m; j ++) { cin >> a[i][j]; if(a[i][j] == '@') { sx = i; sy = j; } } } DFS(sx, sy); cout << ans << endl; } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
<tag>图论</tag>
<tag>搜素算法</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day6]]></title>
<url>%2F2019%2F07%2F23%2FDay6%2F</url>
<content type="text"><![CDATA[Day6今天学习的是 BFS + 存图方法BFS:学起来很容易,但是DEBUG是真的累由于自己比较笨,debug时间太长,没写完知识点待补OJ链接:https://vjudge.net/contest/313171#overviewBFS:广度优先搜索链接:存图方式链式前向星在了解什么是链式前向星之前,我们先来看一下什么是前向星。前向星其实就是一种边集数组。我们先把每条边的起点按照从小到大的顺序排序如果起点一样,那么就按照终点从小到达来排序。并记录下以某个点为起点的所有边在数组中的起始位置和边的数量,那么前向星就构造好了。RescueProblem DescriptionAngel was caught by the MOLIGPY! He was put in prison by Moligpy. The prison is described as a N * M (N, M <= 200) matrix. There are WALLs, ROADs, and GUARDs in the prison.Angel’s friends want to save Angel. Their task is: approach Angel. We assume that “approach Angel” is to get to the position where Angel stays. When there’s a guard in the grid, we must kill him (or her?) to move into the grid. We assume that we moving up, down, right, left takes us 1 unit time, and killing a guard takes 1 unit time, too. And we are strong enough to kill all the guards.You have to calculate the minimal time to approach Angel. (We can move only UP, DOWN, LEFT and RIGHT, to the neighbor grid within bound, of course.)InputFirst line contains two integers stand for N and M.Then N lines follows, every line has M characters. “.” stands for road, “a” stands for Angel, and “r” stands for each of Angel’s friend.Process to the end of the file.OutputFor each test case, your program should output a single integer, standing for the minimal time needed. If such a number does no exist, you should output a line containing “Poor ANGEL has to stay in the prison all his life.”1234567891011Sample Input7 8#.#####.#.a#..r.#..#x.....#..#.##...##...#..............Sample Output13code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990#include<bits/stdc++.h>using namespace std;char a[300][300];int vis[300][300];int n, m;struct node{ int x, y; int step; friend bool operator < (node a, node b) { return a.step > b.step; } //重载运算符,用于自定义优先队列 的排序};int d[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};void BFS(int x1, int y1, int x2, int y2){ memset(vis, 0, sizeof(vis)); //先将全部初始化,方便后面标记 priority_queue<node> q; //优先队列 node e1, e2; e1.x = x1, e1.y = y1, e1.step = 0; q.push(e1); vis[x1][y1] = 1; int ans = -1;//表示不可能只走0步 while(!q.empty()) { e1 = q.top(); q.pop(); if(e1.x == x2 && e1.y == y2) { ans = e1.step; break; } for(int i = 0; i < 4; i ++) { e2.x = e1.x + d[i][0]; e2.y = e1.y + d[i][1]; //遍历寻找,如果不符合条件就continue if(e2.x < 0 || e2.x >= n || e2.y < 0 || e2.y >= m || vis[e2.x][e2.y] == 1 || a[e2.x][e2.y] == '#') continue; else { if(a[e2.x][e2.y] == 'x') e2.step = e1.step + 2; else e2.step = e1.step + 1; } //遍历完一定要把新的数加入队列!! q.push(e2); vis[e2.x][e2.y] = 1; } } if(ans == -1) puts("Poor ANGEL has to stay in the prison all his life."); else cout << ans << endl;}int main(){ int x1, y1, x2, y2; while(~scanf("%d %d",&n,&m)) { for(int i = 0; i < n; i ++) { scanf("%s",&a[i]); } //双重for循环来寻找开始的点和 结束的点 for(int i = 0; i < n; i ++) { for(int j = 0; j < m; j ++) { if(a[i][j] == 'a') { x1 = i; y1 = j; } if(a[i][j] == 'r') { x2 = i; y2 = j; } } } BFS(x1, y1, x2, y2); } return 0;}Red and BlackProblem DescriptionThere is a rectangular room, covered with square tiles. Each tile is colored either red or black. A man is standing on a black tile. From a tile, he can move to one of four adjacent tiles. But he can’t move on red tiles, he can move only on black tiles.Write a program to count the number of black tiles which he can reach by repeating the moves described above.InputThe input consists of multiple data sets. A data set starts with a line containing two positive integers W and H; W and H are the numbers of tiles in the x- and y- directions, respectively. W and H are not more than 20.There are H more lines in the data set, each of which includes W characters. Each character represents the color of a tile as follows.‘.’ - a black tile‘#’ - a red tile‘@’ - a man on a black tile(appears exactly once in a data set)OutputFor each data set, your program should output a line which contains the number of tiles he can reach from the initial tile (including itself).123456789101112131415161718192021222324252627282930313233343536373839404142Sample Input6 9....#......#..............................#@...#.#..#.11 9.#..........#.#######..#.#.....#..#.#.###.#..#.#..@#.#..#.#####.#..#.......#..#########............11 6..#..#..#....#..#..#....#..#..###..#..#..#@...#..#..#....#..#..#..7 7..#.#....#.#..###.###...@...###.###..#.#....#.#..0 0Sample Output4559613code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157#include<bits/stdc++.h>using namespace std;const int mod = 300;int n, m; //n表示行 ,m表示列char a[mod][mod];int vis[mod][mod];int d[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};//struct node{// int x, y;// int step; //用优先队列的时候加上friend bool operator// friend bool operator < (node a, node b)// {// return a.step > b.step;// }//};//优先队列的BFS//void BFS(int x1, int y1)//{// memset(vis, 0, sizeof(vis));//// priority_queue<node> q;// node e1, e2;// e1.x = x1, e1.y = y1;// q.push(e1);// vis[e1.x][e1.y] = 1;// int num = 1;// while(!q.empty())// {// e1 = q.top();// q.pop();// for(int i = 0; i < 4; i ++)// {// e2.x = e1.x + d[i][0];// e2.y = e1.y + d[i][1];// if(e2.x < 0 || e2.x >= n || e2.y < 0 || e2.y >= m || vis[e2.x][e2.y] == 1 || a[e2.x][e2.y] == '#') continue;// else num ++; //e2.step = e1.step + 1;// q.push(e2);// vis[e2.x][e2.y] = 1;// }// }// cout << num << endl;//}//////不是优先队列的BFS//struct node{// int x, y;// int step;//};//void BFS(int x1, int y1)//{// memset(vis, 0, sizeof(vis));//// queue<node> q;// node e1, e2;// e1.x = x1, e1.y = y1;// q.push(e1);// vis[e1.x][e1.y] = 1;// int num = 1;// while(!q.empty())// {// e1 = q.top();// q.pop();// for(int i = 0; i < 4; i ++)// {// e2.x = e1.x + d[i][0];// e2.y = e1.y + d[i][1];// if(e2.x < 0 || e2.x >= n || e2.y < 0 || e2.y >= m || vis[e2.x][e2.y] == 1 || a[e2.x][e2.y] == '#') continue;// else num ++;// q.push(e2);// vis[e2.x][e2.y] = 1;// }// }// cout << num << endl;//}//int main()//{//// int x1, y1, x2, y2;// while(~scanf("%d %d",&m,&n))// {// if(n == 0 && m == 0) break;// for(int i = 0; i < n; i ++)// {// scanf("%s",&a[i]);// }// for(int i = 0; i < n; i ++)// {// for(int j = 0; j < m; j ++)// {// if(a[i][j] == '@')// {// x1 = i;// y1 = j;// }// }// }// BFS(x1, y1);// }// // return 0;//}//DFSint num;void DFS(int x1, int y1){ int xx, yy; a[x1][y1] = '#'; num ++; for(int i = 0; i < 4; i ++) { xx = x1 + d[i][0]; yy = y1 + d[i][1]; if(xx < 0 || xx >= n || yy < 0 || yy >= m || a[xx][yy] == '#') continue; else DFS(xx, yy); }}int main(){ int x1, y1; while(~scanf("%d %d",&m,&n)) { if(n == 0 && m == 0) break; for(int i = 0; i < n; i ++) { scanf("%s", &a[i]); } for(int i = 0; i < n; i ++) { for(int j = 0; j < m; j ++) { if(a[i][j] == '@') { x1 = i; y1 = j; } } } memset(vis, 0, sizeof(vis)); num = 0; DFS(x1, y1); cout << num << endl; } return 0;}Battle CityProblem DescriptionMany of us had played the game “Battle city” in our childhood, and some people (like me) even often play it on computer now.What we are discussing is a simple edition of this game. Given a map that consists of empty spaces, rivers, steel walls and brick walls only. Your task is to get a bonus as soon as possible suppose that no enemies will disturb you (See the following picture).Your tank can’t move through rivers or walls, but it can destroy brick walls by shooting. A brick wall will be turned into empty spaces when you hit it, however, if your shot hit a steel wall, there will be no damage to the wall. In each of your turns, you can choose to move to a neighboring (4 directions, not 8) empty space, or shoot in one of the four directions without a move. The shot will go ahead in that direction, until it go out of the map or hit a wall. If the shot hits a brick wall, the wall will disappear (i.e., in this turn). Well, given the description of a map, the positions of your tank and the target, how many turns will you take at least to arrive there?InputThe input consists of several test cases. The first line of each test case contains two integers M and N (2 <= M, N <= 300). Each of the following M lines contains N uppercase letters, each of which is one of ‘Y’ (you), ‘T’ (target), ‘S’ (steel wall), ‘B’ (brick wall), ‘R’ (river) and ‘E’ (empty space). Both ‘Y’ and ‘T’ appear only once. A test case of M = N = 0 indicates the end of input, and should not be processed.OutputFor each test case, please output the turns you take at least in a separate line. If you can’t arrive at the target, output “-1” instead.12345678Sample Input3 4YBEBEERESSTE0 0Sample Output8code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990#include<iostream>#include<queue>#include<algorithm>#include<cstring>using namespace std;const int mod = 350;const int INF = 5;char a[mod][mod];int vis[mod][mod];int n, k;struct node{ int x, y; int step; friend bool operator < (node a, node b) { return a.step > b.step; }};int d[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};void BFS(int x1, int y1, int x2, int y2){ memset(vis, 0, sizeof(vis)); priority_queue<node> q; node e1, e2; e1.x = x1, e1.y = y1, e1.step = 0; q.push(e1); vis[x1][y1] = 1; int ans = -1; while(!q.empty()) { e1 = q.top(); q.pop(); if(e1.x == x2 && e1.y == y2) { ans = e1.step; break; } for(int i = 0; i < 4; i ++) { e2.x = e1.x + d[i][0]; e2.y = e1.y + d[i][1]; if(e2.x < 0 || e2.x >= n || e2.y < 0 || e2.y >= k || vis[e2.x][e2.y] == 1) continue; else { if(a[e2.x][e2.y] == 'S' || a[e2.x][e2.y] == 'R') continue; if(a[e2.x][e2.y] == 'B') e2.step = e1.step + 2; else e2.step = e1.step + 1; } q.push(e2); vis[e2.x][e2.y] = 1; } } if(ans == -1) puts("-1"); else cout << ans << endl;}int main(){ int x1, x2, y1, y2; while(~scanf("%d %d",&n, &k)) { if(n == 0 && k == 0) break; for(int i = 0; i < n; i ++) { scanf("%s",&a[i]); } for(int i = 0; i < n; i ++) { for(int j = 0; j < k; j ++) { if(a[i][j] == 'Y') { x1 = i; y1 = j; } if(a[i][j] == 'T') { x2 = i; y2 = j; } } } BFS(x1, y1, x2, y2); } return 0;}Catch That CowProblem Description农夫知道一头牛的位置,想要抓住它。农夫和牛都于数轴上 ,农夫起始位于点 N(0<=N<=100000) ,牛位于点 K(0<=K<=100000) 。农夫有两种移动方式: 1、从 X移动到 X-1或X+1 ,每次移动花费一分钟 2、从 X移动到 2*X ,每次移动花费一分钟 假设牛没有意识到农夫的行动,站在原地不。最少要花多少时间才能抓住牛?Input一行: 以空格分隔的两个字母: N 和 KOutput一行: 农夫抓住牛需要的最少时间,单位分钟123456Sample Input5 17Sample Output4Hint农夫使用最短时间抓住牛的方案如下: 5-10-9-18-17, 需要4分钟.code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172#include<iostream>#include<queue>#include<algorithm>#include<cstring>using namespace std;const int mod = 1e5 + 10;int vis[mod];int n, k;struct node{ int x; int step; friend bool operator < (node a, node b) { return a.step > b.step; }};void BFS(int x1, int x2){ memset(vis, 0, sizeof(vis)); priority_queue<node> q; node e1, e2; e1.x = x1, e1.step = 0; vis[e1.x] = 1; q.push(e1); while(!q.empty()) { e1 = q.top(); q.pop(); if(e1.x == x2) break; else { if(e1.x - 1 > 0 && vis[e1.x - 1] == 0) { e2.x = e1.x - 1; e2.step = e1.step + 1; vis[e2.x] = 1; q.push(e2); } if(e1.x + 1 <= 100000 && vis[e1.x + 1] == 0) { e2.x = e1.x + 1; e2.step = e1.step + 1; vis[e2.x] = 1; q.push(e2); } if(e1.x * 2 <= 100000 && vis[e1.x * 2] == 0) { e2.x = e1.x * 2; e2.step = e1.step + 1; vis[e2.x] = 1; q.push(e2); } } } cout << e1.step << endl;}int main(){ while(~scanf("%d %d",&n, &k)) { if(n > k) cout << n - k << endl; else BFS(n, k); } return 0;}Dungeon MasterProblem Description你被困在一个三维的空间中,现在要寻找最短路径逃生!空间由立方体单位构成你每次向上下前后左右移动一个单位需要一分钟你不能对角线移动并且四周封闭是否存在逃出生天的可能性?如果存在,则需要多少时间?Input - 输入输入第一行是一个数表示空间的数量。每个空间的描述的第一行为L,R和C(皆不超过30)。L表示空间的高度。R和C分别表示每层空间的行与列的大小。随后L层地牢,每层R行,每行C个字符。每个字符表示空间的一个单元。’#’表示不可通过单元,’.’表示空白单元。你的起始位置在’S’,出口为’E’。每层空间后都有一个空行。L,R和C均为0时输入结束。Output - 输出每个空间对应一行输出。如果可以逃生,则输出如下Escaped in x minute(s).x为最短脱离时间。如果无法逃生,则输出如下Trapped!1234567891011121314151617181920212223242526Sample Input - 输入样例3 4 5S.....###..##..###.#############.####...###########.#######E1 3 3S###E####0 0 0Sample Output - 输出样例Escaped in 11 minute(s).Trapped!code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126#include<iostream>#include<cstring>#include<queue>using namespace std;const int mod = 30;int L, R, C;char a[mod][mod][mod];int vis[mod][mod][mod];struct node{ int x, y, z; int t; friend bool operator < (node a, node b) { return a.t > b.t; }}s, e, e1;//判断是否到达终点bool yes(node sss){ if(sss.x == e.x && sss.y == e.y && sss.z == e.z) return true; else return false;}// 判断该点是否越界bool check(int x, int y, int z){ if(x >= 0 && x < L && y >= 0 && y < R && z >= 0 && z < C && !vis[x][y][z] && (a[x][y][z] == '.' || a[x][y][z] == 'E')) return true; else return false;}int d[6][3] = { 1, 0, 0, -1, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 1, 0, 0, -1};int ans;void BFS(){ memset(vis, 0, sizeof(vis)); priority_queue<node> q; node e2; e1.x = s.x, e1.y = s.y, e1.z = s.z, e1.t = 0; q.push(e1); vis[e1.x][e1.y][e1.z] = 1; while(!q.empty()) { e1 = q.top(); q.pop(); if(yes(e1)) { ans = e1.t; break; } else { for(int i = 0; i < 6; i ++) { e2.x = e1.x + d[i][0]; e2.y = e1.y + d[i][1]; e2.z = e1.z + d[i][2]; if(check(e2.x, e2.y, e2.z)) { e2.t = e1.t + 1; q.push(e2); vis[e2.x][e2.y][e2.z] = 1; } else continue; } } }}int main(){ while(~scanf("%d %d %d",&L, &R, &C)) { if(L == 0 && R == 0 && C == 0) break; for(int i = 0; i < L; i ++) { for(int j = 0; j < R; j ++) { for(int k = 0; k < C; k ++) { cin >> a[i][j][k]; } } } for(int i = 0; i < L; i ++) { for(int j = 0; j < R; j ++) { for(int k = 0; k < C; k ++) { if(a[i][j][k] == 'S') { s.x = i; s.y = j; s.z = k; } if(a[i][j][k] == 'E') { e.x = i; e.y = j; e.z = k; } } } } BFS(); if(e1.x == e.x && e1.y == e.y && e1.z == e.z) printf("Escaped in %d minute(s).\n", ans); else printf("Trapped!\n"); } return 0;}Robot MotionProblem Description A robot has been programmed to follow the instructions in its path. Instructions for the next direction the robot is to move are laid down in a grid. The possible instructions areN north (up the page)S south (down the page)E east (to the right on the page)W west (to the left on the page)For example, suppose the robot starts on the north (top) side of Grid 1 and starts south (down). The path the robot follows is shown. The robot goes through 10 instructions in the grid before leaving the grid.Compare what happens in Grid 2: the robot goes through 3 instructions only once, and then starts a loop through 8 instructions, and never exits.You are to write a program that determines how long it takes a robot to get out of the grid or how the robot loops around.InputThere will be one or more grids for robots to navigate. The data for each is in the following form. On the first line are three integers separated by blanks: the number of rows in the grid, the number of columns in the grid, and the number of the column in which the robot enters from the north. The possible entry columns are numbered starting with one at the left. Then come the rows of the direction instructions. Each grid will have at least one and at most 10 rows and columns of instructions. The lines of instructions contain only the characters N, S, E, or W with no blanks. The end of input is indicated by a row containing 0 0 0.OutputFor each grid in the input there is one line of output. Either the robot follows a certain number of instructions and exits the grid on any one the four sides or else the robot follows the instructions on a certain number of locations once, and then the instructions on some number of locations repeatedly. The sample input below corresponds to the two grids above and illustrates the two forms of output. The word “step” is always immediately followed by “(s)” whether or not the number before it is 1.1234567891011121314Sample Input3 6 5NEESWEWWWESSSNWWWW4 5 1SESWEEESNWNWEENEWSEN0 0 0Sample Output10 step(s) to exit3 step(s) before a loop of 8 step(s)code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152#include<iostream>#include<cstdio>#include<cstring>using namespace std;char s[12][12];int vis[12][12];int main(){ int a,b,c; while(scanf("%d %d %d",&a,&b,&c)) { if(a==0&&b==0&&c==0) break; for(int i=0;i<a;i++) for(int j=0;j<b;j++) cin>>s[i][j]; int x=0,y=c-1,step=0; memset(vis,0,sizeof(vis)); while(true) { step++; if(s[x][y]=='N'&&!vis[x][y]) { vis[x][y]=step; x--; } else if(s[x][y]=='S'&&!vis[x][y]) { vis[x][y]=step; x++; } else if(s[x][y]=='W'&&!vis[x][y]) { vis[x][y]=step; y--; } else if(s[x][y]=='E'&&!vis[x][y]) { vis[x][y]=step; y++; } if(x<0||x==a||y<0||y==b) { printf("%d step(s) to exit\n",step); break; } else if(vis[x][y]) { printf("%d step(s) before a loop of %d step(s)\n",vis[x][y]-1,step+1-vis[x][y]); break; } } }}Number TransformationProblem DescriptionIn this problem, you are given an integer number s. You can transform any integer number A to another integer number B by adding x to A. This x is an integer number which is a prime factor of A (please note that 1 and A are not being considered as a factor of A). Now, your task is to find the minimum number of transformations required to transform s to another integer number t.InputInput starts with an integer T (≤ 500), denoting the number of test cases.Each case contains two integers: s (1 ≤ s ≤ 100) and t (1 ≤ t ≤ 1000).OutputFor each case, print the case number and the minimum number of transformations needed. If it’s impossible, then print -1.1234567Sample Input26 126 13Sample OutputCase 1: 2Case 2: -1code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<queue>using namespace std;#define INF 0x3f3f3f3fconst int maxx = 1e5;struct node{ int x, step; friend bool operator < (node a, node b) { return a.step > b.step; }};bool vis[10010];int p[10010];int s, t, k, ans;void prime(int n){ k = 0; int m; m = n; for(int i = 2; i <= sqrt(n); i ++) { if(n % i == 0) { p[++ k] = i; while(n % i == 0) n /= i; } } if(n > 1 && m != n) p[++ k] = n;}void BFS(){ priority_queue<node> q; node e1, e2; e1.x = s, e1.step = 0; vis[s] = 1; q.push(e1); bool flag = 0; while(!q.empty()) { e1 = q.top(); q.pop(); if(e1.x == t) { flag = 1; ans = min(ans, e1.step); continue; } memset(p, 0, sizeof(p)); prime(e1.x); for(int i = 1; i <= k; i ++) { e2.x = e1.x + p[i]; e2.step = e1.step + 1; if(e2.x <= t && !vis[e2.x]) { vis[e2.x] = 1; q.push(e2); } } } if(flag) cout << ans << endl; else puts("-1");}int main(){ int n, kase = 0; cin >> n; while(n --) { ans = INF; memset(vis, 0, sizeof(vis)); cin >> s >> t; printf("Case %d: ", ++ kase); if(s == t) { puts("0"); continue; } if(s > t) { puts("-1"); continue; } BFS(); } return 0;}Knight MovesProblem DescriptionA friend of you is doing research on the Traveling Knight Problem (TKP) where you are to find the shortest closed tour of knight moves that visits each square of a given set of n squares on a chessboard exactly once. He thinks that the most difficult part of the problem is determining the smallest number of knight moves between two given squares and that, once you have accomplished this, finding the tour would be easy.Of course you know that it is vice versa. So you offer him to write a program that solves the “difficult” part.Your job is to write a program that takes two squares a and b as input and then determines the number of knight moves on a shortest route from a to b.InputThe input file will contain one or more test cases. Each test case consists of one line containing two squares separated by one space. A square is a string consisting of a letter (a-h) representing the column and a digit (1-8) representing the row on the chessboard.OutputFor each test case, print one line saying “To get from xx to yy takes n knight moves.”.123456789101112131415161718Sample Inpute2 e4a1 b2b2 c3a1 h8a1 h7h8 a1b1 c3f6 f6Sample OutputTo get from e2 to e4 takes 2 knight moves.To get from a1 to b2 takes 4 knight moves.To get from b2 to c3 takes 2 knight moves.To get from a1 to h8 takes 6 knight moves.To get from a1 to h7 takes 5 knight moves.To get from h8 to a1 takes 6 knight moves.To get from b1 to c3 takes 1 knight moves.To get from f6 to f6 takes 0 knight moves.code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364#include<bits/stdc++.h>using namespace std;#define max_v 30int vis[max_v][max_v];int dir[8][2]= {1,-2,2,-1,2,1,1,2,-1,2,-2,1,-2,-1,-1,-2};int ans;int sx, sy, fx, fy;struct node{ int x,y,step;};void BFS(){ memset(vis, 0, sizeof(vis)); queue<node> q; node e1, e2; e1.x = sx; e1.y = sy; e1.step = 0; vis[e1.x][e1.y] = 1; q.push(e1); while(!q.empty()) { e1 = q.front(); q.pop(); if(e1.x == fx && e1.y == fy) { ans = e1.step; return ; } for(int i = 0; i < 8; i ++) { e2.x = e1.x + dir[i][0]; e2.y = e1.y + dir[i][1]; if(e2.x >= 1 && e2.y >= 1 && e2.x <= 8 && e2.y <= 8 && vis[e2.x][e2.y] == 0) { e2.step = e1.step + 1; vis[e2.x][e2.y] = 1; q.push(e2); } } }}int main(){ char x1, x2; int y1, y2; while(~scanf("%c%d %c%d",&x1,&y1,&x2,&y2)) { getchar(); sx=x1-'a'+1; sy=y1; fx=x2-'a'+1; fy=y2; BFS(); printf("To get from %c%d to %c%d takes %d knight moves.\n",x1, y1, x2, y2, ans); } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
<tag>图论</tag>
<tag>搜素算法</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day5]]></title>
<url>%2F2019%2F07%2F22%2FDay5%2F</url>
<content type="text"><![CDATA[Day5今天学习的是二分 + 贪心额,又是艰难的一天题写不完,只能慢慢补题了二分算法二分查找法作为一种常见的查找方法,将原本是线性时间提升到了对数时间范围,大大缩短了搜索时间,但它有一个前提,就是必须在有序数据中进行查找。最基本的二分查找1234567891011121314int binarySearch(int[] A, int target, int n){ int low = 0, high = n, mid; while(low <= high){ mid = low + (high - low) / 2; if(A[mid] == target){ return mid; }else if(A[mid] > target){ high = mid - 1; }else{ low = mid + 1; } } return -1;}需要注意的点:循环的判定条件是:low <= high为了防止数值溢出,mid = low + (high - low)/2当 A[mid]不等于target时,high = mid - 1或low = mid + 1查找目标值区域的左边界/查找与目标值相等的第一个位置/查找第一个不小于目标值数的位置A = [1,3,3,5, 7 ,7,7,7,8,14,14]target = 7return 4123456789101112131415int binarySearchLowerBound(int[] A, int target, int n){ int low = 0, high = n, mid; while(low <= high){ mid = low + (high - low) / 2; if(target <= A[mid]){ high = mid - 1; }else{ low = mid + 1; } } if(low < A.length && A[low] == target) return low; else return -1;}查找目标值区域的右边界/查找与目标值相等的最后一个位置/查找最后一个不大于目标值数的位置A = [1,3,3,5,7,7,7, 7 ,8,14,14]target = 7return 7123456789101112131415int binarySearchUpperBound(int[] A, int target, int n){ int low = 0, high = n, mid; while(low <= high){ mid = low + (high - low) / 2; if(target >= A[mid]){ low = mid + 1; }else{ high = mid - 1; } } if(high >= 0 && A[high] == target) return high; else return -1;}查找最后一个小于目标值的数/查找比目标值小但是最接近目标值的数A = [1,3,3, 5 ,7,7,7,7,8,14,14]target = 7return 312345678910int low = 0, high = n, mid;while(low <= high){ mid = low + (high - low) / 2; if(target <= A[mid]){ high = mid - 1; }else{ low = mid + 1; }}return high < 0 ? -1 : high;查找第一个大于目标值的数/查找比目标值大但是最接近目标值的数A = [1,3,3,5,7,7,7,7, 8 ,14,14]target = 7return 812345678910int low = 0, high = n, mid;while(low <= high){ mid = low + (high - low) / 2; if(target >= A[mid]){ low = mid + 1; }else{ high = mid - 1; }}return low > n ? -1 : low;贪心算法基本认识:在对问题求解时,总是做出在当前看来是最好的选择。不从整体最优上加以考虑,所做出的仅是在某种意义上的局部最优解。贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关。所以对所采用的贪心策略一定要仔细分析其是否满足无后效性。经典例题:哈夫曼树构造价值问题:https://blog.csdn.net/likunkun__/article/details/80258515不完全(可拆分)背包问题:https://blog.csdn.net/likunkun__/article/details/80145612海岸雷达问题:https://blog.csdn.net/likunkun__/article/details/80230259普通字符串变换成回文字符串问题:https://blog.csdn.net/likunkun__/article/details/80230341基本思路:1.建立数学模型来描述问题。2.把求解的问题分成若干个子问题。3.对每一子问题求解,得到子问题的局部最优解。4.把子问题的解局部最优解合成原来解问题的一个解。使用的问题贪心策略适用的前提是:局部最优策略能导致产生全局最优解。实际上,贪心算法适用的情况很少。一般,对一个问题分析是否适用于贪心算法,可以先选择该问题下的几个实际数据进行分析,就可做出判断。贪心策略的选择因为用贪心算法只能通过解局部最优解的策略来达到全局最优解,因此,一定要注意判断问题是否适合采用贪心算法策略,找到的解是否一定是问题的最优解。OJ链接:https://cn.vjudge.net/contest/313049#overviewPieProblem DescriptionMy birthday is coming up and traditionally I’m serving pie. Not just one pie, no, I have a number N of them, of various tastes and of various sizes. F of my friends are coming to my party and each of them gets a piece of pie. This should be one piece of one pie, not several small pieces since that looks messy. This piece can be one whole pie though.My friends are very annoying and if one of them gets a bigger piece than the others, they start complaining. Therefore all of them should get equally sized (but not necessarily equally shaped) pieces, even if this leads to some pie getting spoiled (which is better than spoiling the party). Of course, I want a piece of pie for myself too, and that piece should also be of the same size.What is the largest possible piece size all of us can get? All the pies are cylindrical in shape and they all have the same height 1, but the radii of the pies can be different.InputOne line with a positive integer: the number of test cases. Then for each test case:—One line with two integers N and F with 1 <= N, F <= 10 000: the number of pies and the number of friends.—One line with N integers ri with 1 <= ri <= 10 000: the radii of the pies.OutputFor each test case, output one line with the largest possible volume V such that me and my friends can all get a pie piece of size V. The answer should be given as a floating point number with an absolute error of at most 10^(-3).12345678Sample Input33 34 3 31 24510 51 4 2 3 4 5 6 5 4 2code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051#include<iostream>#include<cmath>#include<algorithm>#define PI acos(-1) // acos(-1) -1的反余弦函数值,等于3.141593using namespace std;int T, n, m, t;double a[10020];bool fun(double x){ double ans = 0; for(int i = 0; i < x; i ++) { ans += (int)(a[i] / x);// 为了防止每个人能分到"最大的馅饼", // 拿每个馅饼的体积去除以单个馅饼能分给每一个人最大的体积,这样得到的就是所有人分到的最大的馅饼体积的和 } if(ans >= m + 1) return 1; return 0;}int main(){ cin >> T; while(T --) { double ans = 0; cin >> n >> m; for(int i = 0; i < n; i ++) { cin >> t; a[i] = t * t * PI; } sort(a, a + n); double l = 0,r = a[n - 1]; double mid = (l + r) / 2; while(r - l >= 0.0000001) { if(fun(mid)) l = mid; else r = mid; mid = (r + l) / 2; } printf("%.4lf\n",mid); } return 0;}/*分馅饼,馅饼高度都为1,所以馅饼的体积V=π*r*r*1=π*r*r;分到最大馅饼的体积是:所有馅饼体积之和/(F+1);(为什么不能是直接所有馅饼之和/(F+1)呢?因为每人只能分到一块,如果讲究平均分的话,一个人分到的就是拼凑起来的“最大的体积”,一个人甚至可能得到超过一块馅饼)最小即为0,然后我们对这两个最大最小值采用二分方法,求出中间符合最大的体积。那么怎么判断那个值就是最大的体积呢?让每个馅饼的体积/能分到最大的体积=能分到的人数,然后将每个馅饼能分到的人数相加,将该人数与F+1做判断比较,然后就是熟悉的套路了。*/Best Cow LineProblem DescriptionFJ is about to take his N (1 ≤ N ≤ 2,000) cows to the annual”Farmer of the Year” competition. In this contest every farmer arranges his cows in a line and herds them past the judges.The contest organizers adopted a new registration scheme this year: simply register the initial letter of every cow in the order they will appear (i.e., If FJ takes Bessie, Sylvia, and Dora in that order he just registers BSD). After the registration phase ends, every group is judged in increasing lexicographic order according to the string of the initials of the cows’ names.FJ is very busy this year and has to hurry back to his farm, so he wants to be judged as early as possible. He decides to rearrange his cows, who have already lined up, before registering them.FJ marks a location for a new line of the competing cows. He then proceeds to marshal the cows from the old line to the new one by repeatedly sending either the first or last cow in the (remainder of the) original line to the end of the new line. When he’s finished, FJ takes his cows for registration in this new order.Given the initial order of his cows, determine the least lexicographic string of initials he can make this way.InputLine 1: A single integer: NLines 2..N+1: Line i+1 contains a single initial (‘A’..’Z’) of the cow in the ith position in the original lineOutputThe least lexicographic string he can make. Every line (except perhaps the last one) contains the initials of 80 cows (‘A’..’Z’) in the new line.12345678910Sample Input6ACDBCBSample OutputABCBCDcode:1234567891011121314151617181920212223242526272829303132333435363738394041#include<iostream>using namespace std;char a [2010];int main(){ int n; cin >> n; int s = 0, e = n - 1, flag = 0; for(int i = 0; i < n; i ++) { cin >> a[i]; } int ans = 0; while(s <= e) { for(int i = 0; i <= e - s; i ++) { if(a[s + i] < a[e - i]) { ans ++; flag = 1; break; } if(a[s + i] > a[e - i]) { flag = 0; ans ++; break; } } if(flag) cout << a[s ++]; else cout << a[e --]; if(ans % 80 == 0) cout << endl; } cout << endl; return 0;}Trailing Zeroes (III)Problem DescriptionYou task is to find minimal natural number N, so that N! contains exactly Q zeroes on the trail in decimal notation. As you know N! = 12…*N. For example, 5! = 120, 120 contains one zero on the trail.InputInput starts with an integer T (≤ 10000), denoting the number of test cases.Each case contains an integer Q (1 ≤ Q ≤ 108) in a line.OutputFor each case, print the case number and N. If no solution is found then print ‘impossible’.123456789Sample Input3125Sample OutputCase 1: 5Case 2: 10Case 3: impossiblecode:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647#include<iostream>#include<algorithm>using namespace std;typedef long long ll;const int maxx = 1e9;ll f(ll n){ ll ans = 0; while(n) { ans += n / 5; n = n / 5; } return ans;}int main(){ int t, q; ll ans; int Case=0; cin >> t; while(t --) { ans = 0; Case ++; int l = 1, r = maxx; ll mid; cin >> q; while(l <= r) { mid = (l + r) >> 1; if(f(mid) == q) { ans = mid; r = mid - 1; } else if(f(mid) < q) l = mid + 1; else r = mid - 1; } if(ans) printf("Case %d: %lld",Case, ans); else printf("Case %d: impossible",Case); cout<<endl; } return 0; }The Frog’s GamesProblem DescriptionThe annual Games in frogs’ kingdom started again. The most famous game is the Ironfrog Triathlon. One test in the Ironfrog Triathlon is jumping. This project requires the frog athletes to jump over the river. The width of the river is L (1<= L <= 1000000000). There are n (0<= n <= 500000) stones lined up in a straight line from one side to the other side of the river. The frogs can only jump through the river, but they can land on the stones. If they fall into the river, theyare out. The frogs was asked to jump at most m (1<= m <= n+1) times. Now the frogs want to know if they want to jump across the river, at least what ability should they have. (That is the frog’s longest jump distance).InputThe input contains several cases. The first line of each case contains three positive integer L, n, and m.Then n lines follow. Each stands for the distance from the starting banks to the nth stone, two stone appear in one place is impossible.OutputFor each case, output a integer standing for the frog’s ability at least they should have.12345678910Sample Input6 1 2225 3 311218Sample Output411code:待补湫湫系列故事——消灭兔子Problem Description湫湫减肥越减越肥!最近,减肥失败的湫湫为发泄心中郁闷,在玩一个消灭免子的游戏。游戏规则很简单,用箭杀死免子即可。箭是一种消耗品,已知有M种不同类型的箭可以选择,并且每种箭都会对兔子造成伤害,对应的伤害值分别为Di(1 <= i <= M),每种箭需要一定的QQ币购买。假设每种箭只能使用一次,每只免子也只能被射一次,请计算要消灭地图上的所有兔子最少需要的QQ币。Input输入数据有多组,每组数据有四行;第一行有两个整数N,M(1 <= N, M <= 100000),分别表示兔子的个数和箭的种类;第二行有N个正整数,分别表示兔子的血量Bi(1 <= i <= N);第三行有M个正整数,表示每把箭所能造成的伤害值Di(1 <= i <= M);第四行有M个正整数,表示每把箭需要花费的QQ币Pi(1 <= i <= M)。特别说明:1、当箭的伤害值大于等于兔子的血量时,就能将兔子杀死;2、血量Bi,箭的伤害值Di,箭的价格Pi,均小于等于100000。Output如果不能杀死所有兔子,请输出”No”,否则,请输出最少的QQ币数,每组输出一行。123456789101112Sample Input3 31 2 32 3 41 2 33 41 2 31 2 3 41 2 3 1Sample Output64code:待补Strange fuctionProblem DescriptionNow, here is a fuction:F(x) = 6 x^7+8x^6+7x^3+5x^2-y*x (0 <= x <=100)Can you find the minimum value when x is between 0 and 100.InputThe first line of the input contains an integer T(1<=T<=100) which means the number of test cases. Then T lines follow, each line has only one real numbers Y.(0 < Y <1e10)OutputJust the minimum value (accurate up to 4 decimal places),when x is between 0 and 100.1234567Sample Input2100200Sample Output-74.4291-178.8534code:1234567891011121314151617181920212223242526272829303132333435363738394041424344#include<bits/stdc++.h>using namespace std;const double mod = 1e-6;double qiu_y(double x){ return 42 * pow(x, 6.0) + 48 * pow(x, 5.0) + 21 * pow(x, 2.0) + 10 * x;}double f(double x, double y){ return 6 * pow(x, 7) + 8 * pow(x, 6) + 7 * pow(x, 3) + 5 * pow(x, 2) - x * y;}int main(){ int t; double l, r, mid, y, res; cin >> t; while(t --) { cin >> y; l = 0.0, r = 100.0; while(r - l > mod) { mid = (r + l) / 2; res = qiu_y(mid); if(res < y) { l = mid + 1e-8; } else { r = mid - 1e-8; } } printf("%0.4lf\n",f(mid, y)); } return 0;}/*相当于y是个常数求 F(x) = 6 * x^7+8*x^6+7*x^3+5*x^2-y*x (0 <= x <=100)这个函数的最小值,令F' = 0,得出x,y的方程,用二分法解方程得x0(易证得x0>=0 && x0<=100),则F'(x0) = 0,由F'' 在[0-100]上恒大于0,所以F'在[0-100]上单增,所以F'(x)<0(x<x0),F'(x)>0(x>x0),所以F(x)在x=x0处取得最小值,所以本题主要就是二分求解方程的x0,然后直接带入x0,y计算即可。*/Can you find it?Problem DescriptionGive you three sequences of numbers A, B, C, then we give you a number X. Now you need to calculate if you can find the three numbers Ai, Bj, Ck, which satisfy the formula Ai+Bj+Ck = X.InputThere are many cases. Every data case is described as followed: In the first line there are three integers L, N, M, in the second line there are L integers represent the sequence A, in the third line there are N integers represent the sequences B, in the forth line there are M integers represent the sequence C. In the fifth line there is an integer S represents there are S integers X to be calculated. 1<=L, N, M<=500, 1<=S<=1000. all the integers are 32-integers.OutputFor each case, firstly you have to print the case number as the form “Case d:”, then for the S queries, you calculate if the formula can be satisfied or not. If satisfied, you print “YES”, otherwise print “NO”.1234567891011121314Sample Input3 3 31 2 31 2 31 2 331410Sample OutputCase 1:NOYESNOcode:待补pairsProblem DescriptionJohn has npoints on the X axis, and their coordinates are (x[i],0),(i=0,1,2,…,n−1)He wants to know how many pairs<a,b>that |x[b]−x[a]|≤k.(a<b)InputThe first line contains a single integer T(about 5), indicating the number of cases.Each test case begins with two integers n,k(1≤n≤100000,1≤k≤109),Next nlines contain an integer xi,means the X coordinates.OutputFor each case, output an integer means how many pairs<a,b>that |x[b]−x[a]|≤k1234567891011121314151617Sample Input25 5-10001001011025 300-1000100101102Sample Output310code:待补Radar InstallationProblem DescriptionAssume the coasting is an infinite straight line. Land is in one side of coasting, sea in the other. Each small island is a point locating in the sea side. And any radar installation, locating on the coasting, can only cover d distance, so an island in the sea can be covered by a radius installation, if the distance between them is at most d.We use Cartesian coordinate system, defining the coasting is the x-axis. The sea side is above x-axis, and the land side below. Given the position of each island in the sea, and given the distance of the coverage of the radar installation, your task is to write a program to find the minimal number of radar installations to cover all the islands. Note that the position of an island is represented by its x-y coordinates.Figure A Sample Input of Radar InstallationsInputThe input consists of several test cases. The first line of each case contains two integers n (1<=n<=1000) and d, where n is the number of islands in the sea and d is the distance of coverage of the radar installation. This is followed by n lines each containing two integers representing the coordinate of the position of each island. Then a blank line follows to separate the cases.The input is terminated by a line containing pair of zerosOutputFor each test case output one line consisting of the test case number followed by the minimal number of radar installations needed. “-1” installation means no solution for that case.12345678910111213Sample Input3 21 2-3 12 11 20 20 0Sample OutputCase 1: 2Case 2: 1code:待补Aggressive cowsProblem DescriptionFarmer John has built a new long barn, with N (2 <= N <= 100,000) stalls. The stalls are located along a straight line at positions x1,…,xN (0 <= xi <= 1,000,000,000).His C (2 <= C <= N) cows don’t like this barn layout and become aggressive towards each other once put into a stall. To prevent the cows from hurting each other, FJ want to assign the cows to the stalls, such that the minimum distance between any two of them is as large as possible. What is the largest minimum distance?InputLine 1: Two space-separated integers: N and CLines 2..N+1: Line i+1 contains an integer stall location, xiOutputLine 1: One integer: the largest minimum distance123456789101112131415Sample Input5 312849Sample Output3HintOUTPUT DETAILS:FJ can put his 3 cows in the stalls at positions 1, 4 and 8, resulting in a minimum distance of 3.Huge input data,scanf is recommended.code:待补River HopscotchProblem DescriptionEvery year the cows hold an event featuring a peculiar version of hopscotch that involves carefully jumping from rock to rock in a river. The excitement takes place on a long, straight river with a rock at the start and another rock at the end, L units away from the start (1 ≤ L ≤ 1,000,000,000). Along the river between the starting and ending rocks, N (0 ≤ N ≤ 50,000) more rocks appear, each at an integral distance Di from the start (0 < Di < L).To play the game, each cow in turn starts at the starting rock and tries to reach the finish at the ending rock, jumping only from rock to rock. Of course, less agile cows never make it to the final rock, ending up instead in the river.Farmer John is proud of his cows and watches this event each year. But as time goes by, he tires of watching the timid cows of the other farmers limp across the short distances between rocks placed too closely together. He plans to remove several rocks in order to increase the shortest distance a cow will have to jump to reach the end. He knows he cannot remove the starting and ending rocks, but he calculates that he has enough resources to remove up to M rocks (0 ≤ M ≤ N).FJ wants to know exactly how much he can increase the shortest distance before he starts removing the rocks. Help Farmer John determine the greatest possible shortest distance a cow has to jump after removing the optimal set of M rocks.InputLine 1: Three space-separated integers: L, N, and MLines 2.. N+1: Each line contains a single integer indicating how far some rock is away from the starting rock. No two rocks share the same position.OutputLine 1: A single integer that is the maximum of the shortest distance a cow has to jump after removing M rocks1234567891011Sample Input25 5 2214112117Sample Output4HintBefore removing any rocks, the shortest jump was a jump of 2 from 0 (the start) to 2. After removing the rocks at 2 and 14, the shortest required jump is a jump of 4 (from 17 to 21 or from 21 to 25).code:待补]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day4]]></title>
<url>%2F2019%2F07%2F21%2FDay4%2F</url>
<content type="text"><![CDATA[Day4第一次积分赛今天打了第一次积分赛,有点小激动虽然没有大佬们那样NB吧,但至少咱们没爆零(以前的事谁有能记得清楚,是不?)归根结底,还是自己太菜了总结一下,积分赛还是学到了很多知识的不一一列举了,都会在代码中体现的(主要是很多新函数的加入!!!)OJ链接:https://hpuoj.com/contest/22/PS:我们学校OJ不太厉害,可能登不上去。。。Nth power of nProblem Description求 n^n 的个位数。输入格式多组输入,处理到文件结束。每组数据输入一个 n。(1≤n≤1e9)输出格式输出 nn 的个位数。样例input123output147Solve:快速幂即可,答案即为 n^n%10复杂度 O(nlog(n))code:1234567891011121314151617181920212223242526#include<bits/stdc++.h>using namespace std;typedef long long ll;const int mod = 1e9;ll quick_pow(ll a, ll b){ ll res = 1; while(b) { if(b & 1) res = res * a % mod; a = a * a % mod; b >>= 1; } return res;}int main(){ int n; while(~scanf("%d",&n)) { cout << quick_pow(n, n) % 10 << endl; } return 0;}复读机的力量Problem DescriptionCodancer: “我好菜啊!”Dicer: “我好菜啊!”Todest: “我好菜啊!”CaprYang: “我好菜啊!”…大佬们又开始装弱了,真正的菜鸡瑟瑟发抖不敢说话。我们规定一个人是复读机当且仅当他说的每一句话都是复读前一个人说的话。我们规定一个人是复读机当且仅当他说的每一句话都是复读前一个人说的话。我们规定一个人是复读机当且仅当他说的每一句话都是复读前一个人说的话。规定一个复读机的熟练度为复读数量的多少。现在给你一段聊天记录,请你找出其中的复读机们。规定一个复读机的熟练度为复读数量的多少。现在给你一段聊天记录,请你找出其中的复读机们。规定一个复读机的熟练度为复读数量的多少。现在给你一段聊天记录,请你找出其中的复读机们。输入格式输入T组,(1≤T≤10)每组第一行输入一个正整数N,表示聊天记录的长度(1≤N≤10000)。接下来N行,每行两个字符串,前一个字符串为姓名,后一个字符为聊天记录。保证所有字符串长度不超过50,保证所有字符串只包含小写字母.输出格式如果没有复读机,输出 “Unbelievable!”(不包含引号)否则按照熟练度从大到小输出所有的复读机,如果熟练度相同,按照字典序从小到大输出。样例input14codancer iamsovegetabledicer iamsovegetabletodest iamsovegetablecapryang iamsovegetableoutputcapryangdicertodest提示数据保证上面大佬们说的话都是瞎话。Solve:只要有一次某个人不是复读的就不是复读机第一个人一定不是复读机使用 map<string,bool> 判断这个人是否是复读机使用 map<string,int> 记录这个人复读的次数用结构体记录排序复杂度 O(n * log(n))code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061#include<bits/stdc++.h>using namespace std;struct node{ string x,y;}p[10005];struct nod{ string na; int fo;}pp[10005];bool cmp(nod m,nod n){ if(m.fo==n.fo) return m.na<n.na; return m.fo>n.fo;}int main(){ int t,n; cin>>t; string x,y; while(t--) { cin>>n; set<string> se; map<string,int> ma; map<string,int> mp; for(int i=0;i<n;i++) { cin>>p[i].x>>p[i].y; se.insert(p[i].x); ma[p[i].x]=1; } ma[p[0].x]=0; for(int i=1;i<n;i++) { if(p[i].y==p[i-1].y) mp[p[i].x]++; if(p[i].y!=p[i-1].y) ma[p[i].x]=0; } int pos=0; for(set<string>::iterator it=se.begin();it!=se.end();it++) { if(ma[*it]) { pp[pos].na=*it; pp[pos].fo=mp[*it]; pos++; } } if(pos==0) puts("Unbelievable!"); else { sort(pp,pp+pos,cmp); for(int i=0;i<pos;i++) { cout<<pp[i].na<<endl; } } }}官方code:123456789101112131415161718192021222324252627282930313233343536373839404142434445#include<bits/stdc++.h>using namespace std;const int N = 1e6+100;struct peo{ string name; int num;};vector<peo> all;map<string,bool> jud;map<string,int> num;string a[N],b[N];set<string> name;bool cmp(peo a,peo b){ if(a.num==b.num) return a.name<b.name; return a.num>b.num;}int main(){ int T; cin>>T; while(T--){ int n; jud.clear();num.clear();name.clear();all.clear(); cin>>n; for(int i=1;i<=n;i++) cin>>a[i]>>b[i],jud[a[i]]=1,num[a[i]]=0,name.insert(a[i]); jud[a[1]]=0; for(int i=2;i<=n;i++){ if(b[i]!=b[i-1]){ jud[a[i]]=0; } num[a[i]]++; } for(auto v:name){ if(jud[v]) all.push_back({v,num[v]}); } sort(all.begin(),all.end(),cmp); if(all.size()==0){ cout<<"Unbelievable!"<<endl; } else{ for(auto v:all) cout<<v.name<<endl; } } return 0;}无穷的小数Problem Description在十进制下,我们能够很轻易地判断一个小数的位数是有穷的或无穷的,但是把这个小数用二进制表示出的情况下其有穷性和无穷性就会发生改变,比如十进制下的 0.5 ,在二进制下的值为 0.1 ;十进制下的 0.75 ,在二进制下的值为 0.11 ;十进制下的 0.6 ,在二进制下的值为 0.1001100……给你一个十进制的小数,判断其在二进制表示下小数位数是否无穷。输入格式多组输入,处理到文件结束每组数据输入一个六位的小数 n.(0≤n\<1)输出格式如果在二进制下小数位数是有穷的,输出”YES”,否则输出”NO”.样例input0.5000000.6000000.750000outputYESNOYESSolve:由于只有后六位,先乘上 106 防止爆精度。按照最普通的算法,每次乘以 2 再对 106 取余当循环次数超过某一个值时,即可判定为无穷code:1234567891011121314151617181920212223242526272829303132#include<bits/stdc++.h>using namespace std;typedef long long ll;const int mod = 1e9;int main(){ double n; while(~scanf("%lf",&n)) { int i = 0; int flag = 0; while(i <= 10) { n *= 2; if(n == int(n)) { flag = 1; break; } i ++; } if(flag) cout << "YES" << endl; else cout << "NO" << endl; } return 0;}/*小数转换成二进制就是每次乘以2直到等于1.如果一个小数在二进制表示下小数位数是无穷的,意思就是无论它乘以几次2,都不会正好等于1。我们只需要乘以2一定的次数,如果出现1,就不是无穷的,反之即无穷的。*/官方code:12345678910111213141516171819202122232425#include<bits/stdc++.h>using namespace std;int main(){ double y; while(scanf("%lf",&y)!=EOF){ y*=10000000; bool flag=0; long long x=(long long)y; int num=0; while(1){ if(x==0) break; if(num>=200){ flag=1;break; } num++; x=2*x; if(x>=10000000) x-=10000000; if(x==0) break; } if(flag) puts("NO"); else puts("YES"); } return 0;}Special StringProblem Description我们定义一个字符串S为Special String只要这个字符串满足下面这些条件:1.这个串是回文的,即把这个字符串正着读和反着读相同,如abba和aca,而ba和abca则不是。2.26个小写字母必须全部出现3.这个串的长度为偶数。对于给定的S,判断它是否是Special String.输入格式输入一个只由小写字母组成的字符串S。(1≤|S|≤1e5)输出格式如果这个字符串是Special String,输出”YE5”,否则输出”N0”样例inputaaaaoutputN0inputabcdefghijklmnopqrstuvwxyzzyxwvutsrqponmlkjihgfedcbaoutputYE5PS:如果这一题不过的,请仔细看题,仔细看题!!!Solve:签到题,按题意要求模拟即可是 YE5 和 N0code:12345678910111213141516171819202122232425262728293031323334353637383940#include<bits/stdc++.h>using namespace std;int main(){ string s; cin >> s; if(s.size() % 2 != 0) { puts("N0"); return 0; } int len = s.size(); int ans = len - 1; set<char> st; set<char> :: iterator it; int flag = 0; for(int i = 0; i <= len / 2; i ++) { st.insert(s[i]); } for(it = st.begin(); it != st.end(); it ++) { for(int i = 'a'; i <= 'z'; i ++) { if(st.count(i) == 0) flag = 1;//不是全部有 } } for(int i = 0;i <= len / 2; i ++) { if(s[i] != s[ans --]) { flag = 1; } } if(flag) puts("N0"); else puts("YE5"); return 0;}官方code:12345678910111213141516171819202122232425262728293031323334#include<bits/stdc++.h>using namespace std;bool check(string s){ string c=s; reverse(c.begin(), c.end()); return s==c;}pair<int,int> pii;int main(){ pii.first=1; pii.second=2; pii=make_pair(1,2); //cout<<pii.first<<' '<<pii.second<<endl; string s; cin>>s; bool flag=0; int l=s.length(); if(l&1) flag=1; if(!check(s)) flag=1; int num[27]; memset(num,0,sizeof(num)); for(int i=0;i<l;i++){ num[s[i]-'a']++; } for(int i=0;i<26;i++){ if(num[i]==0){ flag=1;break; } } if(flag) cout<<"N0"<<endl; else cout<<"YE5"<<endl; return 0;}Max GcdProblem Description一个数组a,现在你需要删除某一项使得它们的gcd最大,求出这个最大值。输入格式第一行输入一个正整数n,表示数组的大小,接下来一行n个数,第i个数为ai。(2≤n≤1e5,1≤ai≤1e9)输出格式输出删除掉某个数以后的gcd的最大值。样例input42 4 8 1output2input41 2 3 4output1提示样例一:删除第四个元素后,2,4,8的最大公因子为2。样例二:无论删除哪一个,最大公因子都为1。Solve:维护前缀 gcd 数组 pre 和后缀 gcd 数组 od删除第 i 个数之后剩余数的 gcd 即为 gcd(prei−1, odi+1)线性枚举即可, 复杂度 O(n)两个都是官方的,学习一下新知识code:123456789101112131415161718192021222324//前缀后缀解法#include<bits/stdc++.h>using namespace std;const int N = 1e5 + 100;long long a[N];long long pre[N], sa[N];int main(){ int n; cin >> n; for(int i = 1; i <= n; i ++) cin >> a[i]; pre[1] = a[1], sa[n] = a[n]; for(int i = 2; i <= n; i ++) pre[i] = __gcd(pre[i - 1], a[i]); for(int i = n - 1; i >= 1; i --) sa[i] = __gcd(sa[i + 1], a[i]); long long ans = max(pre[n - 1], sa[2]); for(int i = 2; i <= n - 1; i ++) { ans = max(ans, __gcd(pre[i - 1],sa[i + 1])); } cout << ans << endl; return 0;}code:1234567891011121314151617181920212223242526272829//贪心解法#include<bits/stdc++.h>using namespace std;const int maxn = 1e5 + 10;int a[maxn];bool cmp(int x,int y){ return x > y;}int gcd(int a,int b){ return b ? gcd(b,a % b) : a;}int main(){ int n; scanf("%d",&n); for (int i = 0;i < n;i ++) scanf("%d",&a[i]); sort(a,a + n,cmp); int ans = a[0],now = a[0]; for (int i = 1;i < n;i ++) { ans = max(gcd(ans,a[i]),now); now = gcd(now,a[i]); } printf("%d\n",ans); return 0;}Count Prime PairsProblem Description对于数组a,如果i≠j并且ai+aj是一个质数,那么我们就称(i,j)为质数对,计算数组中质数对的个数。输入格式第一行输入一个n,表示数组的长度,接下来n个整数,第i个数代表ai。(1≤n≤100000,0≤ai≤100)输出格式输出数组中质数对的个数。样例input31 2 3output4提示样例说明:a1+a2,a2+a1,a2+a3,a3+a2都为质数,总共有四对。Solve:注意到 ai 的范围很小,我们可以先打出 [1, 200] 以内的质数表O(n) 或 O(nlog(n)) 的统计每个数出现的次数对于第 i 个质数 pi,和数组中第 j 个元素 aj,答案应该累加上 pi − aj 出现的次数注意 pi = 2 ∗ aj 的情况,应该加上 aj 出现的次数减去 1code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>using namespace std;int prime[350];int v[250];void init(){ for(int i = 0; i < 250; i ++) { prime[i] = 1; } prime[0] = prime[1] = 0; for(int i = 2; i < 250; i ++) { for(int j = 2; j * i < 250; j ++) { prime[i * j] = 0; } }}int main(){ int n, a; scanf("%d",&n); for(int i = 0; i < 200; i ++) v[i] = 0; for(int i = 1; i <= n; i ++) { cin >> a; v[a] ++; } init(); int ans = 0; for(int i = 1; i <= 200; i ++) { if(prime[i] == 1) { for(int j = 0; j <= i / 2; j ++) { if(j != i - j) ans = ans + v[j] * v[i - j] * 2; else ans = ans + v[j] * (v[j] - 1); } } } cout << ans << endl; return 0;}官方code:1234567891011121314151617181920212223242526272829303132333435363738394041#include<bits/stdc++.h>using namespace std;const int N = 1e6+100;bool check(int x){ if(x==1) return 0; if(x==2) return 1; for(int i=2;i*i<=x;i++){ if(x%i==0) return 0; } return 1;}vector<int> pr;void init(){ for(int i=1;i<=250;i++){ if(check(i)) pr.push_back(i); }}int a[N];int vis[300];int main(){ init(); memset(vis,0,sizeof(vis)); long long ans=0; int n; cin>>n; for(int i=1;i<=n;i++) cin>>a[i],vis[a[i]]++; for(int i=0;i<(int)pr.size();i++){ int now=pr[i]; for(int j=1;j<=n;j++){ if(now>=a[j]){ if(now==(a[j]*2)) ans+=vis[a[j]]-1; else{ if(vis[a[j]]&&vis[now-a[j]]) ans+=vis[now-a[j]]; } } } } cout<<ans<<endl; return 0;}平行线Problem Description“大猩猩为什么不喜欢平行线?”“因为平行线没有相交”哈哈哈哈哈哈哈哈哈为了管理动物园不听话的大猩猩们,动物管理员Boctorio 决定去远方的ACM之城找一些平行线,当他逛到一个神奇的店铺时,他发现了一副黑色的图,上面依稀可见一些白色的点。Boctorio 询问店铺老板这幅画是什么,老板说:“天机不可泄露”。等Boctorio仔细端详了一会这幅画后,他惊讶的发现其中所蕴含的奥秘。向店铺老板道谢后,他拿着刚买的这幅画,就连忙赶回动物园。输入格式输入一个数 n(1≤n≤1000),表示点的个数。接下来n行,每行两个整数 xi,yi(1≤xi,yi≤1e9),表示第i个点。数据保证没有重复的点输出格式输出用这些点所能表示出来的平行线段的对数。(两条不同的线段重合也算为平行)样例input60 01 01 13 13 35 4output10Solve:对(yi−yj)/(xi−xj) 用 gcd 约分后用 pair 存储利用 map 统计每个斜率的线段条数, 假设为 num, 那么斜率k 的贡献即为 num*(num−1)/2累加不同的斜率的贡献即可复杂度 O(n^2log(n^2))code:12345678910111213141516171819202122232425262728293031323334353637#include<bits/stdc++.h>using namespace std;int x[1005], y[1005];int main(){ int n; cin >> n; set<pair<int, int> > se; map<pair<int, int> ,int> mp; for(int i = 0; i < n; i ++) cin >> x[i] >> y[i]; for(int i = 0; i < n; i ++) { for(int j = i + 1; j < n; j ++) { int dx = x[j] - x[i]; int dy = y[j] - y[i]; int mid = __gcd(dx, dy); dx /= mid; dy /= mid; mp[{dx, dy}] ++; se.insert({dx, dy}); } } int ans = 0; for(set<pair<int, int> > :: iterator it = se.begin(); it != se.end(); it ++) { ans += (mp[*it] * (mp[*it] - 1)) / 2; } cout << ans << endl; return 0;}/*先开一个集合和一个字典用来存储点数据然后用gcd来找最大公约数,找到最小的分数,用 map存储约化后的斜率n * (n - 1) / 2*/官方code:123456789101112131415161718192021222324252627282930313233#include<bits/stdc++.h>using namespace std;const int N = 2000;typedef long long ll;int x[N],y[N];int main(){ int n; cin>>n; map<pair<int,int> ,int> k; set<pair<long long,long long>> all; long long ans=0; for(int i=1;i<=n;i++) cin>>x[i]>>y[i]; for(int i=1;i<=n;i++){ for(int j=i+1;j<=n;j++){ int dx=x[j]-x[i]; int dy=y[j]-y[i]; if(dx<0&&dy<0){ dx=-dx; dy=-dy; } long long gc=__gcd(dx,dy); dx/=gc;dy/=gc; k[{dx,dy}]++; all.insert({dx,dy}); } } for(auto v:all){ ans+=(k[v]*(k[v]-1)/2); } cout<<ans<<endl; return 0;}Area of polygonsProblem Description现在有a个边长为1的正方形,b个半径为1的圆,c个边长为1的等边三角形,现在你随机拿出一个图形,求这个图形面积的期望。输入格式第一行输入一个T,代表输入的组数。(1≤T≤100)接下来T行,每行三个数字a,b,c(1≤a,b,c≤1000)。输出格式输出T行,对于每一组输入,输出面积的期望,小数点后保留三位小数。样例input31 2 34 5 67 8 9output1.4301.4871.501提示圆周率为3.1415926535897Solve:初中数学题答案即为 a+bPI+c√3/4/(a+b+c)code:123456789101112131415161718192021#include<bits/stdc++.h>using namespace std;typedef long long ll;const float P = 3.1415926535897;int main(){ int n; cin >> n; while(n --) { double a, b, c; cin >> a >> b >> c; double ans = 0; ans = (a + b * P + c * sqrt(3) / 4) / (a + b + c); printf("%.3lf\n",ans); } return 0;}双色球Problem Description双色球投注区分为红色球号码区和蓝色球号码区,红色球号码区由1-33共三十三个号码组成,蓝色球号码区由1-16共十六个号码组成。投注时选择6个红色球号码和1个蓝色球号码组成一注进行单式投注。其中奖规则为:一等奖(6+1)二等奖(6+0)三等奖(5+1)四等奖(5+0、4+1)五等奖(4+0、3+1)六等奖(2+1、1+1、0+1)其中(a+b)即为有a个红色球,b个蓝色球与开奖某个数字相同(只与数字有关,与位置无关)。现在你有 n 张双色球彩票,以及本场彩票开奖结果,请你求出这 n 张彩票获得的最高奖。输入格式第一行输入一个 n ,表示 n 张彩票接下来 n 行,每行 7 个数字,表示每张彩票的选号,其中前六个位红色球,后一个为蓝色球。接下来一行,输入 7 个数字,表示开奖结果,其中前六个为红色球,后一个为蓝色球。输出格式输出所有彩票中能获得的最高等级奖,若无,则输出”0”。样例input52 17 21 28 30 32 102 12 17 29 30 31 159 10 19 25 26 30 126 8 18 29 30 31 1013 14 21 22 27 32 86 7 12 19 27 28 12output6input32 17 21 28 30 32 102 12 17 29 30 31 159 10 19 25 26 30 126 8 18 29 30 31 10output6提示彩票六个红色球数字均为从小到大排列Solve:只有 7 颗球,暴力模拟即可code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152#include<bits/stdc++.h>using namespace std;typedef long long ll;const int mod = 1e9;struct node{ int b[10];}d[1000];int a[40];int main(){ int n; cin >> n; for(int i = 0; i < n; i ++) { for(int j = 0; j < 7; j ++) { cin >> d[i].b[j]; } } for(int i = 0; i < 7; i ++) cin >> a[i]; int awd = 7, fin_awd = 7; for(int i = 0; i < n; i ++) { int flag = 0; int ans = 0; for(int j = 0; j < 6; j ++) { if(binary_search(a, a + 6, d[i].b[j])) { ans ++; } } if(a[6] == d[i].b[6]) flag = 1; if(ans == 0 && flag == 1) awd = 6; if(ans == 1 && flag == 1) awd = 6; if(ans == 2 && flag == 1) awd = 6; if(ans == 3 && flag == 1) awd = 5; if(ans == 4 && flag == 0) awd = 5; if(ans == 4 && flag == 1) awd = 4; if(ans == 5 && flag == 0) awd = 4; if(ans == 5 && flag == 1) awd = 3; if(ans == 6 && flag == 0) awd = 2; if(ans == 6 && flag == 1) awd = 1; fin_awd = min(awd, fin_awd); } cout << fin_awd % 7 << endl; return 0;}官方code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748#include<bits/stdc++.h>using namespace std;pair<int,int> solve(vector<int> a,vector<int> b){ int num[34]; memset(num,0,sizeof(num)); int r=0; int bl=0; for(int i=0;i<6;i++){ num[a[i]]++; } for(int i=0;i<6;i++){ if(num[b[i]]) r++; } if(a[6]==b[6]) bl=1; return {r,bl};}int cal(pair<int,int> pii){ if(pii.first==6&&pii.second==1) return 1; if(pii.first==6&&pii.second==0) return 2; if(pii.first==5&&pii.second==1) return 3; if((pii.first==5&&pii.second==0)||(pii.first==4&&pii.second==1)) return 4; if((pii.first==4&&pii.second==0)||(pii.first==3&&pii.second==1)) return 5; if((pii.first==2&&pii.second==1)||(pii.first==1&&pii.second==1)||(pii.first==0&&pii.second==1)) return 6; return 99999;}const int N = 1e3+100;vector<int> a[N];int main(){ int n; cin>>n; for(int i=1;i<=n;i++){ int x; for(int j=0;j<7;j++){ cin>>x; a[i].push_back(x); } } int ans=7; vector<int> b(7); for(int i=0;i<7;i++) cin>>b[i]; for(int i=1;i<=n;i++) { ans=min(ans,cal(solve(a[i],b))); } if(ans==7) ans=0; cout<<ans<<endl; return 0;}Remainder Minimization 2019Problem Description给你一个区间[L,R],在这个区间内找到两个不同的数字i,j,使得(i∗j)%2019的值最小。输入格式输入两个数 L,R,(1≤L\<R≤1e9)输出格式如题样例input4 5output20input2020 2040output2Solve:当 L 和 R 的差值大于 2019 的时候,其中必定含有 2019 的倍数,此时答案为 0否则暴力枚举code:123456789101112131415161718192021222324252627#include<bits/stdc++.h>using namespace std;typedef long long ll;const int mod = 2019;int main(){ int l, r; cin >> l >> r; int minn = 6666666; if((r - l) > 2019) minn = 0; else { for(int i = l; i <= r; i ++) { for(int j = i; j <= r; j ++) { if(i != j && (i % mod) * (j % mod) % 2019 < minn) { minn = (i % mod) * (j % mod) % 2019; } } } } cout << minn << endl; return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day3]]></title>
<url>%2F2019%2F07%2F20%2FDay3%2F</url>
<content type="text"><![CDATA[Day3今天学习的是 STL + 栈 + 队列栈和队列还好,以前接触过,STL就不行了,对我来说只是听说过,没用过全新的知识点一定要打好基础!!!因为学的比较慢,此次没有把题补完,下次补上未完待续~~~OJ链接:https://cn.vjudge.net/contest/312177Windows Message QueueProblem DescriptionMessage queue is the basic fundamental of windows system. For each process, the system maintains a message queue. If something happens to this process, such as mouse click, text change, the system will add a message to the queue. Meanwhile, the process will do a loop for getting message from the queue according to the priority value if it is not empty. Note that the less priority value means the higher priority. In this problem, you are asked to simulate the message queue for putting messages to and getting message from the message queue.InputThere’s only one test case in the input. Each line is a command, “GET” or “PUT”, which means getting message or putting message. If the command is “PUT”, there’re one string means the message name and two integer means the parameter and priority followed by. There will be at most 60000 command. Note that one message can appear twice or more and if two messages have the same priority, the one comes first will be processed first.(i.e., FIFO for the same priority.) Process to the end-of-file.OutputFor each “GET” command, output the command getting from the message queue with the name and parameter in one line. If there’s no message in the queue, output “EMPTY QUEUE!”. There’s no output for “PUT” command.123456789101112Sample InputGETPUT msg1 10 5PUT msg2 10 4GETGETGETSample OutputEMPTY QUEUE!msg2 10msg1 10EMPTY QUEUE!code:待补~Train Problem IProblem DescriptionAs the new term comes, the Ignatius Train Station is very busy nowadays. A lot of student want to get back to school by train(because the trains in the Ignatius Train Station is the fastest all over the world ^v^).But here comes a problem, there is only one railway where all the trains stop. So all the trains come in from one side and get out from the other side. For this problem, if train A gets into the railway first, and then train B gets into the railway before train A leaves, train A can’t leave until train B leaves.The pictures below figure out the problem. Now the problem for you is, there are at most 9 trains in the station, all the trains has an ID(numbered from 1 to n), the trains get into the railway in an order O1, your task is to determine whether the trains can get out in an order O2. InputThe input contains several test cases. Each test case consists of an integer, the number of trains, and two strings, the order of the trains come in:O1, and the order of the trains leave:O2. The input is terminated by the end of file. More details in the Sample Input.OutputThe output contains a string “No.” if you can’t exchange O2 to O1, or you should output a line contains “Yes.”, and then output your way in exchanging the order(you should output “in” for a train getting into the railway, and “out” for a train getting out of the railway). Print a line contains “FINISH” after each test case. More details in the Sample Output.12345678910111213141516171819202122Sample Input3 123 3213 123 312Sample OutputYes.inininoutoutoutFINISHNo.FINISHTip:For the first Sample Input, we let train 1 get in, then train 2 and train 3.So now train 3 is at the top of the railway, so train 3 can leave first, then train 2 and train 1.In the second Sample input, we should let train 3 leave first, so we have to let train 1 get in, then train 2 and train 3.Now we can let train 3 leave.But after that we can't let train 1 leave before train 2, because train 2 is at the top of the railway at the moment.So we output "No.".code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849#include<bits/stdc++.h>using namespace std;int main(){ int n; string id1, id2, res; while(~scanf("%d",&n)) { cin >> id1 >> id2; stack<char> s; queue<string> q; int i, j; int flag = 0; for(int i = 0, j = 0; i < n && j <= n;) { if(s.empty() || s.top() != id2[i]) { if(j == n) { cout << "No.\nFINISH\n"; flag = 1; break; } s.push(id1[j]); j ++; q.push("in"); } else { s.pop(); i ++; q.push("out"); } } if(flag) continue; else { cout << "Yes.\n"; while(!q.empty()) { cout << q.front() << endl; q.pop(); } } cout << "FINISH" << endl; } return 0;}RailsProblem DescriptionThere is a famous railway station in PopPush City. Country there is incredibly hilly. The station was built in last century. Unfortunately, funds were extremely limited that time.It was possible to establish only a surface track. Moreover, it turned out that the station could be only a dead-end one (see picture) and due to lack of available space it could have only one track.The local tradition is that every train arriving from the direction A continues in the direction B with coaches reorganized in some way. Assume that the train arriving from the direction A has N <= 1000 coaches numbered in increasing order 1, 2, …, N.The chief for train reorganizations must know whether it is possible to marshal coaches continuing in the direction B so that their order will be a1, a2, …, aN. Help him and write a program that decides whether it is possible to get the required order of coaches.You can assume that single coaches can be disconnected from the train before they enter the station and that they can move themselves until they are on the track in the direction B. You can also suppose that at any time there can be located as many coaches as necessary in the station. But once a coach has entered the station it cannot return to the track in the direction A and also once it has left the station in the direction B it cannot return back to the station.InputThe input consists of blocks of lines. Each block except the last describes one train and possibly more requirements for its reorganization. In the first line of the block there is the integer N described above. In each of the next lines of the block there is a permutation of 1, 2, …, N. The last line of the block contains just 0.The last block consists of just one line containing 0.OutputThe output contains the lines corresponding to the lines with permutations in the input. A line of the output contains Yes if it is possible to marshal the coaches in the order required on the corresponding line of the input. Otherwise it contains No. In addition, there is one empty line after the lines corresponding to one block of the input. There is no line in the output corresponding to the last null’’ block of the input.1234567891011121314Sample Input51 2 3 4 55 4 1 2 3066 5 4 3 2 100Sample OutputYesNoYescode:12345678910111213141516171819202122232425262728293031323334353637383940414243#include<cstdio>#include<iostream>#include<cstring>#include<stack>using namespace std;int a[1010];int main(){ int t; while(~scanf("%d",&t) && t) { while(1) { stack<int> s; scanf("%d",&a[0]); if(!a[0]) { puts(""); break; } for(int i = 1; i < t; i ++) { cin >> a[i]; } int ans = 0; for(int i = 1; i <= t; i ++) { s.push(i); while(!s.empty() && s.top() == a[ans]) { s.pop(); ans ++; } } if(s.empty()) puts("Yes"); else puts("No"); } } return 0;}{A} + {B}Problem Description给你两个集合,要求{A} + {B}.注:同一个集合中不会有两个相同的元素.Input每组输入数据分为三行,第一行有两个数字n,m(0<n,m<=10000),分别表示集合A和集合B的元素个数.后两行分别表示集合A和集合B.每个元素为不超出int范围的整数,每个元素之间有一个空格隔开.Output针对每组数据输出一行数据,表示合并后的集合,要求从小到大输出,每个元素之间有一个空格隔开.12345678910Sample Input1 212 31 211 2Sample Output1 2 31 2code:1234567891011121314151617181920212223242526272829303132333435#include<bits/stdc++.h>using namespace std;typedef long long ll;const int INF = 0x3f3f3f3f;const int mod = 1e9;int main(){ int n, m, x, y; set<int> :: iterator it;//遍历器 while(~scanf("%d %d",&n, &m)) { set<int> st; for(int i = 0; i < n; i ++) { scanf("%d",&x); st.insert((x)); } for(int i = 0; i < m; i ++) { scanf("%d",&y); st.insert(y); } it = st.begin(); cout << *it; it ++; for(; it != st.end(); it ++) { cout << " " << *it; } puts(""); } return 0;}水果Problem Description夏天来了好开心啊,呵呵,好多好多水果Joe经营着一个不大的水果店.他认为生存之道就是经营最受顾客欢迎的水果.现在他想要一份水果销售情况的明细表,这样Joe就可以很容易掌握所有水果的销售情况了.Input第一行正整数N(0<N<=10)表示有N组测试数据.每组测试数据的第一行是一个整数M(0<M<=100),表示工有M次成功的交易.其后有M行数据,每行表示一次交易,由水果名称(小写字母组成,长度不超过80),水果产地(小写字母组成,长度不超过80)和交易的水果数目(正整数,不超过100)组成.Output对于每一组测试数据,请你输出一份排版格式正确(请分析样本输出)的水果销售情况明细表.这份明细表包括所有水果的产地,名称和销售数目的信息.水果先按产地分类,产地按字母顺序排列;同一产地的水果按照名称排序,名称按字母顺序排序.两组测试数据之间有一个空行.最后一组测试数据之后没有空行.1234567891011121314Sample Input15apple shandong 3pineapple guangdong 1sugarcane guangdong 1pineapple guangdong 3pineapple guangdong 1Sample Outputguangdong |----pineapple(5) |----sugarcane(1)shandong |----apple(3)code:12345678910111213141516171819202122232425262728293031323334353637// map的嵌套使用#include<bits/stdc++.h>using namespace std;struct node{ map<string, int> count;};int main(){ int n, m; cin >> n; while(n --) { map<string, node> mp; int x, num; string fruit, place; cin >> m; for(int i = 0; i < m; i ++) { cin >> fruit >> place >> num; mp[place].count[fruit] += num; } map<string, int> :: iterator it1; map<string, node> :: iterator it2; for(it2 = mp.begin(); it2 != mp.end(); it2 ++) { cout << it2 -> first << endl; for(it1 = mp[it2 -> first].count.begin(); it1 != mp[it2 -> first].count.end(); it1 ++) { cout << " |----" << it1 -> first << "(" << it1 -> second << ")" << endl; } } if(n) cout << endl; } return 0;}Let the Balloon RiseProblem DescriptionContest time again! How excited it is to see balloons floating around. But to tell you a secret, the judges’ favorite time is guessing the most popular problem. When the contest is over, they will count the balloons of each color and find the result.This year, they decide to leave this lovely job to you.InputInput contains multiple test cases. Each test case starts with a number N (0 < N <= 1000) – the total number of balloons distributed. The next N lines contain one color each. The color of a balloon is a string of up to 15 lower-case letters.A test case with N = 0 terminates the input and this test case is not to be processed.OutputFor each case, print the color of balloon for the most popular problem on a single line. It is guaranteed that there is a unique solution for each test case.123456789101112131415Sample Input5greenredblueredred3pinkorangepink0Sample Outputredpinkcode:12345678910111213141516171819202122232425262728#include<bits/stdc++.h>using namespace std;const int maxx = 10010;int main(){ int n; char name[20]; while(~scanf("%d",&n)) { if( n == 0) break; map<string, int> balloons; for(int i = 0; i < n; i ++) { cin >> name; balloons[name] ++; } map<string, int> :: iterator p, m; p = m = balloons.begin(); for(; p != balloons.end(); p ++) { if(p -> second > m -> second) m = p; } cout << m -> first << endl; } return 0;}不重复数字Problem Description给出N个数,要求把其中重复的去掉,只保留第一次出现的数。例如,给出的数为1 2 18 3 3 19 2 3 6 5 4,其中2和3有重复,去除后的结果为1 2 18 3 19 6 5 4。Input输入第一行为正整数T,表示有T组数据。接下来每组数据包括两行,第一行为正整数N,表示有N个数。第二行为要去重的N个正整数。Output对于每组数据,输出一行,为去重后剩下的数字,数字之间用一个空格隔开。1234567891011121314151617181920Sample Input2111 2 18 3 3 19 2 3 6 5 461 2 3 4 5 6Sample Output1 2 18 3 19 6 5 41 2 3 4 5 6Hint对于30%的数据,1 <= N <= 100,给出的数不大于100,均为非负整数;对于50%的数据,1 <= N <= 10000,给出的数不大于10000,均为非负整数;对于100%的数据,1 <= N <= 50000,给出的数在32位有符号整数范围内。提示:由于数据量很大,使用C++的同学请使用scanf和printf来进行输入输出操作,以免浪费不必要的时间。code:1234567891011121314151617181920212223242526272829303132333435363738#include<cstdio>#include<set>#include<iostream>using namespace std;typedef long long ll;const int INF = 0x3f3f3f3f;const int mod = 1e9;int main(){ int t, n, m; cin >> t; while(t --) { scanf("%d",&n); set<int> st; int a[50010]; int l = 0; for(int i = 0; i < n; i ++) { scanf("%d",&m); if(st.count(m) == 0) { st.insert(m); a[l ++] = m; } } for(int i = 0; i < l - 1; i ++) { cout << a[i] << " "; } printf("%d\n", a[l - 1]); st.clear(); } return 0;}Andy’s First DictionaryProblem DescriptionAndy, 8, has a dream - he wants to produce his very own dictionary. This is not an easy task for him, as the number of words that he knows is, well, not quite enough. Instead of thinking up all the words himself, he has a briliant idea. From his bookshelf he would pick one of his favourite story books, from which he would copy out all the distinct words. By arranging the words inalphabetical order, he is done! Of course, it is a really time-consuming job, and this is where a computer program is helpful.You are asked to write a program that lists all the different words in the input text. In this problem, a word is defined as a consecutive sequence of alphabets, in upper and/or lower case. Words with only one letter are also to be considered. Furthermore, your program must be CaSe InSeNsItIvE. For example, words like “Apple”, “apple” or “APPLE” must be considered the same.InputThe input file is a text with no more than 5000 lines. An input line has at most 200 characters. Inputis terminated by EOF.OutputYour output should give a list of different words that appears in the input text, one in a line. Thewords should all be in lower case, sorted in alphabetical order. You can be sure that he number ofdistinct words in the text does not exceed 5000.123456789101112131415161718192021222324252627Sample InputAdventures in DisneylandTwo blondes were going to Disneyland when they came to a fork in theroad. The sign read: "Disneyland Left."So they went home.Sample Outputaadventuresblondescamedisneylandforkgoinghomeinleftreadroadsignsothetheytotwowentwerewhencode:1234567891011121314151617181920212223242526272829#include <bits/stdc++.h>using namespace std;int main(){ string s; set<string> se; while (cin >> s) { for (int i = 0; i < s.size(); i++) { if (s[i] >= 'A' && s[i] <= 'Z') s[i] += 32; else if (s[i] >= 'a' && s[i] <= 'z') s[i] = s[i]; else s[i] = ' '; } string mi; stringstream mid(s); while (mid >> mi) { se.insert(mi); } } for (set<string>::iterator it = se.begin(); it != se.end(); it++) { cout << *it << endl; }}A and B and Compilation ErrorsProblem DescriptionA and B are preparing themselves for programming contests.B loves to debug his code. But before he runs the solution and starts debugging, he has to first compile the code.Initially, the compiler displayed n compilation errors, each of them is represented as a positive integer. After some effort, B managed to fix some mistake and then another one mistake.However, despite the fact that B is sure that he corrected the two errors, he can not understand exactly what compilation errors disappeared — the compiler of the language which B uses shows errors in the new order every time! B is sure that unlike many other programming languages, compilation errors for his programming language do not depend on each other, that is, if you correct one error, the set of other error does not change.Can you help B find out exactly what two errors he corrected?InputThe first line of the input contains integer n (3 ≤ n ≤ 105) — the initial number of compilation errors.The second line contains n space-separated integers a1, a2, …, an (1 ≤ ai ≤ 109) — the errors the compiler displayed for the first time.The third line contains n - 1 space-separated integers b1, b2, …, bn - 1 — the errors displayed at the second compilation. It is guaranteed that the sequence in the third line contains all numbers of the second string except for exactly one.The fourth line contains n - 2 space-separated integers с1, с2, …, сn - 2 — the errors displayed at the third compilation. It is guaranteed that the sequence in the fourth line contains all numbers of the third line except for exactly one.OutputPrint two numbers on a single line: the numbers of the compilation errors that disappeared after B made the first and the second correction, respectively.1234567891011121314151617181920ExamplesInput51 5 8 123 7123 7 5 15 1 7Output8123Input61 4 3 3 5 73 7 5 4 34 3 7 5Output13NoteIn the first test sample B first corrects the error number 8, then the error number 123.In the second test sample B first corrects the error number 1, then the error number 3. Note that if there are multiple errors with the same number, B can correct only one of them in one step.code:123456789101112131415161718192021222324252627282930#include<iostream>#include<cstring>#include<algorithm>#include<cmath>using namespace std;const int maxx = 1e9;int main(){ int t, x, a = 0, b = 0, c = 0; scanf("%d",&t); for(int i = 0; i < t; i ++) { cin >> x; a += x; } for(int i = 0; i < t - 1; i ++) { cin >> x; b += x; } for(int i = 0; i < t - 2; i ++) { cin >> x; c += x; } printf("%d\n%d\n",a - b, b - c); return 0;}排列2Problem DescriptionRay又对数字的列产生了兴趣:现有四张卡片,用这四张卡片能排列出很多不同的4位数,要求按从小到大的顺序输出这些4位数。Input每组数据占一行,代表四张卡片上的数字(0<=数字<=9),如果四张卡片都是0,则输入结束。Output对每组卡片按从小到大的顺序输出所有能由这四张卡片组成的4位数,千位数字相同的在同一行,同一行中每个四位数间用空格分隔。每组输出数据间空一行,最后一组数据后面没有空行。123456789101112131415161718Sample Input1 2 3 41 1 2 30 1 2 30 0 0 0Sample Output1234 1243 1324 1342 1423 14322134 2143 2314 2341 2413 24313124 3142 3214 3241 3412 34214123 4132 4213 4231 4312 43211123 1132 1213 1231 1312 13212113 2131 23113112 3121 32111023 1032 1203 1230 1302 13202013 2031 2103 2130 2301 23103012 3021 3102 3120 3201 3210code:12345678910111213141516171819202122232425262728293031323334353637#include<bits/stdc++.h>using namespace std;int a[4];int main(){ int t = 0, tmp; while(scanf("%d %d %d %d",&a[0], &a[1], &a[2], &a[3]) && a[0] + a[1] + a[2] + a[3]) { if(t) puts(""); t = 1; int flag = 1; do { if(a[0] == 0) continue; if(flag) { cout << a[0] << a[1] << a[2] << a[3]; flag = 0; } else if(tmp == a[0]) { cout << " " << a[0] << a[1] << a[2] << a[3]; } else { puts(""); cout << a[0] << a[1] << a[2] << a[3]; } tmp = a[0]; } while(next_permutation(a, a + 4)); puts(""); } return 0;}Ignatius and the Princess IIProblem DescriptionNow our hero finds the door to the BEelzebub feng5166. He opens the door and finds feng5166 is about to kill our pretty Princess. But now the BEelzebub has to beat our hero first. feng5166 says, “I have three question for you, if you can work them out, I will release the Princess, or you will be my dinner, too.” Ignatius says confidently, “OK, at last, I will save the Princess.”“Now I will show you the first problem.” feng5166 says, “Given a sequence of number 1 to N, we define that 1,2,3…N-1,N is the smallest sequence among all the sequence which can be composed with number 1 to N(each number can be and should be use only once in this problem). So it’s easy to see the second smallest sequence is 1,2,3…N,N-1. Now I will give you two numbers, N and M. You should tell me the Mth smallest sequence which is composed with number 1 to N. It’s easy, isn’t is? Hahahahaha……”Can you help Ignatius to solve this problem?InputThe input contains several test cases. Each test case consists of two numbers, N and M(1<=N<=1000, 1<=M<=10000). You may assume that there is always a sequence satisfied the BEelzebub’s demand. The input is terminated by the end of file.OutputFor each test case, you only have to output the sequence satisfied the BEelzebub’s demand. When output a sequence, you should print a space between two numbers, but do not output any spaces after the last number.123456Sample Input6 411 8Sample Output1 2 3 5 6 41 2 3 4 5 6 7 9 8 11 10code:123456789101112131415161718192021222324252627282930#include<iostream>#include<cstring>#include<algorithm>#include<cmath>using namespace std;const int maxx = 1e9;int a[1010];int main(){ int n, m; while(~scanf("%d %d",&n, &m)) { for(int i = 1; i <= n; i ++) { a[i] = i; } for(int i = 1; i < m; i ++) { next_permutation(a + 1, a + n + 1); } cout << a[1]; for(int i = 2; i <= n; i ++) { cout << " " << a[i]; } puts(""); } return 0;}ACboy needs your help again!Problem DescriptionACboy was kidnapped!!he miss his mother very much and is very scare now.You can’t image how dark the room he was put into is, so poor :(.As a smart ACMer, you want to get ACboy out of the monster’s labyrinth.But when you arrive at the gate of the maze, the monste say :” I have heard that you are very clever, but if can’t solve my problems, you will die with ACboy.”The problems of the monster is shown on the wall:Each problem’s first line is a integer N(the number of commands), and a word “FIFO” or “FILO”.(you are very happy because you know “FIFO” stands for “First In First Out”, and “FILO” means “First In Last Out”).and the following N lines, each line is “IN M” or “OUT”, (M represent a integer).and the answer of a problem is a passowrd of a door, so if you want to rescue ACboy, answer the problem carefully!InputThe input contains multiple test cases.The first line has one integer,represent the number oftest cases.And the input of each subproblem are described above.OutputFor each command “OUT”, you should output a integer depend on the word is “FIFO” or “FILO”, or a word “None” if you don’t have any integer.12345678910111213141516171819202122232425262728293031323334Sample Input44 FIFOIN 1IN 2OUTOUT4 FILOIN 1IN 2OUTOUT5 FIFOIN 1IN 2OUTOUTOUT5 FILOIN 1IN 2OUTIN 3OUTSample Output122112None23code:待补~]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day2]]></title>
<url>%2F2019%2F07%2F19%2FDay2%2F</url>
<content type="text"><![CDATA[Day2今天学习的是GCD + 素筛 + 快速幂因为以前有过基础,学的还行OJ链接:https://cn.vjudge.net/contest/312021Pseudoprime numbersProblem DescriptionFermat’s theorem states that for any prime number p and for any integer a > 1, ap = a (mod p). That is, if we raise a to the pth power and divide by p,the remainder is a. Some (but not very many) non-prime values of p, known as base-a pseudoprimes, have this property for some a.(And some, known as Carmichael Numbers, are base-a pseudoprimes for all a.)Given 2 < p ≤ 1000000000 and 1 < a < p, determine whether or not p is a base-a pseudoprime.InputInput contains several test cases followed by a line containing “0 0”. Each test case consists of a line containing p and a.OutputFor each test case, output “yes” if p is a base-a pseudoprime; otherwise output “no”.123456789101112131415Sample Input3 210 3341 2341 31105 21105 30 0Sample Outputnonoyesnoyesyescode:1234567891011121314151617181920212223242526272829303132333435363738394041#include<cstdio>#include<cstring>using namespace std;typedef long long ll;const int mod = 1e9 + 7;ll quick_pow(ll a, ll n){ ll res = 1; ll m = n; while(m) { if(m & 1) res = res * a % n; a = a * a % n; m >>= 1; } return res;}bool prime(int n){ for(int i = 2;i * i < n; i ++) { if(n % i == 0) return false; } return true;}int main(){ int n, m; while(~scanf("%d %d",&n, &m) && n) { if(prime(n)) puts("no"); else if(quick_pow(m, n) == m) puts("yes"); else puts("no"); }// 求出若p不是素数并且p^a是否等于a,若等于则输出yes,否则输出no return 0;}Raising Modulo NumbersProblem DescriptionPeople are different. Some secretly read magazines full of interesting girls’ pictures, others create an A-bomb in their cellar,others like using Windows, and some like difficult mathematical games. Latest marketing research shows, that this market segment was so far underestimated and that there is lack of such games. This kind of game was thus included into the KOKODáKH. The rules follow:Each player chooses two numbers Ai and Bi and writes them on a slip of paper. Others cannot see the numbers. In a given moment all players show their numbers to the others. The goal is to determine the sum of all expressions Ai Bifrom all players including oneself and determine the remainder after division by a given number M. The winner is the one whofirst determines the correct result. According to the players’ experience it is possible to increase the difficulty by choosing higher numbers.You should write a program that calculates the result and is able to find out who won the game.InputThe input consists of Z assignments. The number of them is given by the single positive integer Z appearing on the first line of input.Then the assignements follow. Each assignement begins with line containing an integer M (1 <= M <= 45000). The sum will be divided by this number.Next line contains number of players H (1 <= H <= 45000). Next exactly H lines follow. On each line,there are exactly two numbers Ai and Bi separated by space. Both numbers cannot be equal zero at the same time.OutputFor each assingnement there is the only one line of output. On this line, there is a number, the result of expression(A1B1+A2B2+ … +AHBH)mod M.123456789101112131415161718Sample Input31642 33 44 55 63612312374859 30293821713 18132Sample Output21319513code:123456789101112131415161718192021222324252627282930313233343536373839#include<cstdio>#include<cstring>#include<iostream>using namespace std;typedef long long ll;ll quick_pow(ll a, ll b, ll mod){ ll res = 1; while(b) { if(b & 1) res = res * a % mod; a = a * a % mod; b >>= 1; } return res;}int main(){ int t, n, M, a, b; cin >> t; while(t --) { cin >> M; cin >> n; ll ans = 0; for(int i = 0; i < n; i ++) { cin >> a >> b; ans += quick_pow(a, b, M); } cout << ans % M << endl; } return 0;}Wolf and RabbitProblem DescriptionThere is a hill with n holes around. The holes are signed from 0 to n-1. A rabbit must hide in one of the holes. A wolf searches the rabbit in anticlockwise order. The first hole he get into is the one signed with 0. Then he will get into the hole every m holes. For example, m=2 and n=6, the wolf will get into the holes which are signed 0,2,4,0.If the rabbit hides in the hole which signed 1,3 or 5, she will survive. So we call these holes the safe holes.InputThe input starts with a positive integer P which indicates the number of test cases. Then on the following P lines,each line consists 2 positive integer m and n(0<m,n<2147483648).OutputFor each input m n, if safe holes exist, you should output “YES”, else output “NO” in a single line.1234567Sample Input21 22 2Sample OutputNOYEScode:12345678910111213141516171819202122232425#include<iostream>#include<cstring>#include<algorithm>#include<cmath>using namespace std;const int maxx=1e5;int gcd(int a, int b){ return !b ? a : gcd(b, a % b);}int main(){ int p, n, m; cin >> p; while(p --) { cin >> n >> m; if(gcd(n, m) == 1) cout << "NO" << endl; else cout << "YES" << endl; } return 0;}CakeProblem Description一次生日Party可能有p人或者q人参加,现准备有一个大蛋糕.问最少要将蛋糕切成多少块(每块大小不一定相等),才能使p人或者q人出席的任何一种情况,都能平均将蛋糕分食.Input每行有两个数p和q.Output输出最少要将蛋糕切成多少块.123456789Sample Input2 3Sample Output4Hint将蛋糕切成大小分别为1/3,1/3,1/6,1/6的四块即满足要求.当2个人来时,每人可以吃1/3+1/6=1/2 , 1/2块。当3个人来时,每人可以吃1/6+1/6=1/3 , 1/3, 1/3块。code:12345678910111213141516171819202122232425#include<bits/stdc++.h>using namespace std;int gcd(int a, int b){ return !b ? a : gcd(b, a % b);}int main(){ int n, m ; while(~scanf("%d %d",&n, &m)) { cout << n + m - gcd(n, m) << endl; } return 0;}/*如果实在看不懂提题意,记住规律就好了,下面是较为好理解的题解将蛋糕切成几块,我想可以把它理解为切多少刀更加易懂。开始思考的是依照蛋糕的大小来计算,结果涉及到了浮点型数据处理,求余,求商等让人很乱,结果当然也不能AC,所以果断弃了。一个数a的因数b,放在这道题中可以使人理解成,想要把蛋糕分成a块,先切b刀,(一次切的长度为蛋糕的半径)再在剩余的b份中,平均分成a/b份,每份需要再切a/b-1刀,其余蛋糕切a-b刀,共切a刀。而如果另一个数c与a有公因数b,则设第一次切好后蛋糕摆放没有变,则需要先切b刀,在平均每份切c/b-1刀,共再切c-b刀,而为了达到块数最小,尽量使用第一次切好的刀缝。第一次的b刀已经不用切取。故最终需要切a+c-d次,分成a+c-d块。由此可见,为了得到最小块数,需要d最大,是两个数的最大公约数。*/又见GCDProblem Description有三个正整数a,b,c(0<a,b,c<10^6),其中c不等于b。若a和c的最大公约数为b,现已知a和b,求满足条件的最小的c。Input第一行输入一个n,表示有n组测试数据,接下来的n行,每行输入两个正整数a,b。Output输出对应的c,每组测试数据占一行。1234567Sample Input26 212 4Sample Output48code:12345678910111213141516171819202122232425262728293031#include<iostream>#include<cstring>#include<algorithm>#include<cmath>using namespace std;const int maxx=1e5;int gcd(int a, int b){ return !b ? a : gcd(b, a % b);}int main(){ int n; int a, b; int ans; cin >> n; while(n --) { cin >> a >> b; int i; for(i = 1;;i ++) { if(b == gcd(a, i) && b != i) break; } cout << i << endl; } return 0;}最小公倍数Problem Description给定两个正整数,计算这两个数的最小公倍数。Input输入包含多组测试数据,每组只有一行,包括两个不大于1000的正整数.Output对于每个测试用例,给出这两个数的最小公倍数,每个实例输出一行。1234Sample Input10 14Sample Output70code:12345678910111213141516171819202122#include<iostream>#include<cstring>#include<algorithm>#include<cmath>using namespace std;const int maxx=1e5;int gcd(int a, int b){ return !b ? a : gcd(b, a % b);}int main(){ int a, b; while(scanf("%d %d",&a, &b)!=EOF) { cout << a * b / gcd(a, b) << endl; } return 0;}素数判定Problem Description对于表达式n^2+n+41,当n在(x,y)范围内取整数值时(包括x,y)(-39<=x<y<=50),判定该表达式的值是否都为素数。Input输入数据有多组,每组占一行,由两个整数x,y组成,当x=0,y=0时,表示输入结束,该行不做处理。Output对于每个给定范围内的取值,如果表达式的值都为素数,则输出”OK”,否则请输出“Sorry”,每组输出占一行。12345Sample Input0 10 0Sample OutputOKcode:12345678910111213141516171819202122232425262728#include<iostream>#include<cstring>#include<algorithm>#include<cmath>using namespace std;const int maxx=1e5;int main(){ int x, y; while(scanf("%d %d",&x, &y)!=EOF) { if(x == 0 && y == 0) break; int flag = 0; int ans; for(int n = x; n <= y; n ++) { ans = n * n + n + 41; for(int i = 2; i <= sqrt(ans); i ++) { if(ans % i == 0) flag = 1; } } if(flag) cout << "Sorry" << endl; else cout << "OK" << endl; } return 0;}分拆素数和Problem Description把一个偶数拆成两个不同素数的和,有几种拆法呢?Input输入包含一些正的偶数,其值不会超过10000,个数不会超过500,若遇0,则结束。Output对应每个偶数,输出其拆成不同素数的个数,每个结果占一行。1234567Sample Input30260Sample Output32code:12345678910111213141516171819202122232425262728293031323334353637383940#include<iostream>#include<cstring>#include<algorithm>#include<cmath>using namespace std;const int maxx = 10001;bool a[maxx];void isprim(){ int i, j; memset(a, true, sizeof(a)); for(i = 3; i < maxx; i ++) { for(j = 2; j < i; j ++) { if(i % j == 0) a[i] = false; } }}int main(){ int n; isprim(); a[0] = a[1] = false; a[2] = true; while(scanf("%d", &n)!=EOF) { if(n == 0) break; int ans = 0; for(int i = 2; i < n / 2; i ++) { if(a[i] && a[n - i]) ans ++; } cout << ans << endl; } //2 3 5 7 11 13 17 19 23 29 return 0;}美素数Problem Description小明对数的研究比较热爱,一谈到数,脑子里就涌现出好多数的问题,今天,小明想考考你对素数的认识。问题是这样的:一个十进制数,如果是素数,而且它的各位数字和也是素数,则称之为“美素数”,如29,本身是素数,而且2+9 = 11也是素数,所以它是美素数。给定一个区间,你能计算出这个区间内有多少个美素数吗?Input第一行输入一个正整数T,表示总共有T组数据(T <= 10000)。接下来共T行,每行输入两个整数L,R(1<= L <= R <= 1000000),表示区间的左值和右值。Output对于每组数据,先输出Case数,然后输出区间内美素数的个数(包括端点值L,R)。每组数据占一行,具体输出格式参见样例。123456789Sample Input31 1002 23 19Sample OutputCase #1: 14Case #2: 1Case #3: 4code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354//美素数,双重打表#include<bits/stdc++.h>using namespace std;#define mod 1000000+5bool a[mod];int ans[mod];void isprime(){ int n, m; memset(a, true, sizeof(a)); a[0] = a[1]= false; for(int i = 2; i < mod; i ++) { for(int j = 2; j * i < mod; j ++) { a[i * j] = false; } }}int SUM(int n){ int sum = 0; while(n) { sum += n % 10; n /= 10; } return sum;}int main(){ int t, n, m; isprime(); memset(ans, 0, sizeof(ans)); int shu = 1, num = 0; for(int i = 2; i < mod; i ++) { if(a[i] && a[SUM(i)]) num ++; ans[i] = num; } cin >> t; while(t --) { cin >> n >> m; printf("Case #%d: %d\n",shu ++, ans[m] - ans[n - 1]); } return 0;}Key SetProblem Descriptionsoda has a set Swith n integers {1,2,…,n}. A set is called key set if the sum of integers in the set is an even number. He wants to know how many nonempty subsets of Sare key set.InputThere are multiple test cases. The first line of input contains an integer T(1≤T≤10^5),indicating the number of test cases. For each test case: The first line contains an integer n(1≤n≤109), the number of integers in the set.OutputFor each test case, output the number of key sets modulo 1000000007.1234567891011Sample Input41234Sample Output0137code:12345678910111213141516171819202122232425262728293031323334//规律题#include<bits/stdc++.h>using namespace std;typedef long long ll;const int INF = 0x3f3f3f3f;const int mod = 1000000007;ll quick_pow(ll a, ll n){ ll res = 1; while(n) { if(n & 1) res = res * a % mod; a = a * a % mod; n >>= 1; } return res % mod;}int main(){ int t, n; cin >> t; while(t --) { cin >> n; cout << quick_pow(2, n - 1) - 1 << endl; } return 0;}//2 ^ (n - 1) - 1人见人爱A^BProblem Description求A^B的最后三位数表示的整数。说明:A^B的含义是“A的B次方”Input输入数据包含多个测试实例,每个实例占一行,由两个正整数A和B组成(1<=A,B<=10000),如果A=0, B=0,则表示输入数据的结束,不做处理。Output对于每个测试实例,请输出A^B的最后三位表示的整数,每个输出占一行。123456789Sample Input2 312 66789 100000 0Sample Output89841code:12345678910111213141516171819202122232425262728293031#include<iostream>#include<cstring>#include<algorithm>#include<cmath>using namespace std;const int mod = 1e9;typedef long long ll;ll quick_pow(ll a, ll n){ ll res = 1; while(n) { if(n & 1) res = res * a % mod; a = a * a % mod; n >>= 1; } return res % mod;}int main(){ int x, y; while(scanf("%d %d",&x, &y)!=EOF) { if(x == 0 && y == 0) break; cout << quick_pow(x, y) % 1000 << endl; } return 0;}Rightmost DigitProblem DescriptionGiven a positive integer N, you should output the most right digit of N^N.InputThe input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow.Each test case contains a single positive integer N(1<=N<=1,000,000,000).OutputFor each test case, you should output the rightmost digit of N^N.1234567891011Sample Input234Sample Output76HintIn the first case, 3 * 3 * 3 = 27, so the rightmost digit is 7.In the second case, 4 * 4 * 4 * 4 = 256, so the rightmost digit is 6.code:12345678910111213141516171819202122232425262728293031#include<iostream>#include<cstring>#include<algorithm>#include<cmath>using namespace std;const int mod = 1e9;typedef long long ll;ll quick_pow(ll x, ll n){ ll res = 1; while(n) { if(n & 1) res = res * x % mod; x = x * x % mod; n >>= 1; } return res % mod;}int main(){ int n, m; cin >> n; while(n --) { cin >> m; cout << quick_pow(m, m) % 10 << endl; } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Day1]]></title>
<url>%2F2019%2F07%2F18%2F40%E5%A4%A9acm%E9%9B%86%E8%AE%ADDay1%2F</url>
<content type="text"><![CDATA[Day1今天学习的是sort + 结构体 + 简单数学 + 暴力比较菜,学习的比较慢,勉强能掌握OJ链接:https://cn.vjudge.net/contest/312050从这个OJ开始,往后的OJ链接只需要在网上输入每个题的名称就能找到对应的OJ前m大的数Problem Description还记得Gardon给小希布置的那个作业么?(上次比赛的1005)其实小希已经找回了原来的那张数表,现在她想确认一下她的答案是否正确,但是整个的答案是很庞大的表,小希只想让你把答案中最大的M个数告诉她就可以了。给定一个包含N(N<=3000)个正整数的序列,每个数不超过5000,对它们两两相加得到的N*(N-1)/2个和,求出其中前M大的数(M<=1000)并按从大到小的顺序排列。Input输入可能包含多组数据,其中每组数据包括两行:第一行两个数N和M,第二行N个数,表示该序列。Output对于输入的每组数据,输出M个数,表示结果。输出应当按照从大到小的顺序排列。Sample Input12344 41 2 3 44 55 3 6 4Sample Output127 6 5 511 10 9 9 8Solve:直接开大数组,暴力code:12345678910111213141516171819202122232425262728293031323334353637383940#include<bits/stdc++.h>using namespace std;int cmp(int a, int b){ return a b;}int n, m;int a[3001];int b[5000000];int main(){ while(scanf("%d %d",&n, &m)!=EOF) { for(int i = 0; i < n; i ++) { cin >a[i]; } int t = 0; sort(a, a + n, cmp); int ans = 0; for(int i = ans + 1; i < n; i ++) { b[t ++] = a[i] + a[ans]; if(i == n - 1 && ans != n ) { i = ans + 1; ans ++; } } sort(b, b + t, cmp); for(int i = 0; i < m; i ++) { if(i == 0) cout << b[0]; else cout << ' ' << b[i]; } cout << endl; } return 0;}稳定排序Problem Description大家都知道,快速排序是不稳定的排序方法。如果对于数组中出现的任意a[i],aj,其中a[i]==a[j],在进行排序以后a[i]一定出现在a[j]之前,则认为该排序是稳定的。某高校招生办得到一份成绩列表,上面记录了考生名字和考生成绩。并且对其使用了某排序算法按成绩进行递减排序。现在请你判断一下该排序算法是否正确,如果正确的话,则判断该排序算法是否为稳定的。Input本题目包含多组输入,请处理到文件结束。对于每组数据,第一行有一个正整数N(0<N<300),代表成绩列表中的考生数目。接下来有N行,每一行有一个字符串代表考生名字(长度不超过50,仅包含’a’~’z’),和一个整数代表考生分数(小于500)。其中名字和成绩用一个空格隔开。再接下来又有N行,是上述列表经过某排序算法以后生成的一个序列。格式同上。Output对于每组数据,如果算法是正确并且稳定的,就在一行里面输出”Right”。如果算法是正确的但不是稳定的,就在一行里面输出”Not Stable”,并且在下面输出正确稳定排序的列表,格式同输入。如果该算法是错误的,就在一行里面输出”Error”,并且在下面输出正确稳定排序的列表,格式同输入。注意,本题目不考虑该排序算法是错误的,但结果是正确的这样的意外情况。Sample Input1234567891011121314151617181920213aa 10bb 10cc 20cc 20bb 10aa 103aa 10bb 10cc 20cc 20aa 10bb 103aa 10bb 10cc 20aa 10bb 10cc 20Sample Output123456789Not Stablecc 20aa 10bb 10RightErrorcc 20aa 10bb 10Solve: 看清题意,慢慢理清思路code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475#include<bits/stdc++.h>using namespace std;struct node{ string name; int sorce, id;}stu[301], stu_1[301];//比较函数,若分数相同,则先出现的标记并按递增的方式排序int cmp1(node a,node b){ if(a.sorce == b.sorce) return a.id < b.id; return a.sorce b.sorce;}int main(){ int n; while(scanf("%d",&n)!=EOF) { for(int i = 0; i < n; i ++) { cin >stu[i].name >stu[i].sorce; stu[i].id = i; } for(int i = 0; i < n; i ++) { cin >stu_1[i].name >stu_1[i].sorce; } //正确排序首先给出的序列 sort(stu, stu + n, cmp1); int flag = 0; //做标记 for(int i = 0; i < n - 1; i ++) { //这个是经过体面意思排序过的,直接通过分数的排序判断是否稳定 if(stu_1[i].sorce < stu_1[i + 1].sorce) { flag = 1;//表示错误 break; } } if(flag) { puts("Error"); for(int i = 0; i < n; i ++) { cout << stu[i].name << " " << stu[i].sorce << endl; } } else { //判断是否稳定 for(int i = 0; i < n; i ++) { if(stu[i].name != stu_1[i].name) { flag = 1;//不稳定 break; } } if(flag) { puts("Not Stable"); for(int i = 0; i < n; i ++) { cout << stu[i].name << " " << stu[i].sorce << endl; } } else { puts("Right"); } } } return 0;}开门人和关门人Problem Description每天第一个到机房的人要把门打开,最后一个离开的人要把门关好。现有一堆杂乱的机房签到、签离记录,请根据记录找出当天开门和关门的人。Input测试输入的第一行给出记录的总天数N ( 0 )。下面列出了N天的记录。每天的记录在第一行给出记录的条目数M ( 0 ),下面是M行,每行的格式为证件号码 签到时间 签离时间其中时间按“小时:分钟:秒钟”(各占2位)给出,证件号码是长度不超过15的字符串。Output对每一天的记录输出1行,即当天开门和关门人的证件号码,中间用1空格分隔。注意:在裁判的标准测试输入中,所有记录保证完整,每个人的签到时间在签离时间之前,且没有多人同时签到或者签离的情况。Sample Input1234567891031ME3021112225321 00:00:00 23:59:592EE301218 08:05:35 20:56:35MA301134 12:35:45 21:40:423CS301111 15:30:28 17:00:10SC3021234 08:00:00 11:25:25CS301133 21:45:00 21:58:40Sample Output123ME3021112225321 ME3021112225321EE301218 MA301134SC3021234 CS301133Solve: 注意时间的转化code:123456789101112131415161718192021222324252627282930313233343536#include<bits/stdc++.h>using namespace std;struct node{ char name[20]; int s_hour,s_min,s_sec; int e_hour,e_min,e_sec; int s, e;}a[1000];int cmp1(node a, node b){ return a.s < b.s;}int cmp2(node a, node b){ return a.e b.e;}int main(){ int n, m; cin >n; while(n --) { cin >m; for(int i = 0; i < m; i ++) { scanf("%s %d:%d:%d %d:%d:%d",&a[i].name, &a[i].s_hour,&a[i].s_min,&a[i].s_sec, &a[i].e_hour, &a[i].e_min, &a[i].e_sec); a[i].s = a[i].s_hour * 3600 + a[i].s_min * 60 + a[i].s_sec; a[i].e = a[i].e_hour * 3600 + a[i].e_min * 60 + a[i].e_sec; } sort(a, a + m, cmp1); cout << a[0].name << ' '; sort(a, a + m, cmp2); cout << a[0].name << endl; } return 0;}EXCEL排序Problem DescriptionExcel可以对一组纪录按任意指定列排序。现请你编写程序实现类似功能。Input测试输入包含若干测试用例。每个测试用例的第1行包含两个整数 N (<=100000) 和 C,其中 N 是纪录的条数,C 是指定排序的列号。以下有 N行,每行包含一条学生纪录。每条学生纪录由学号(6位数字,同组测试中没有重复的学号)、姓名(不超过8位且不包含空格的字符串)、成绩(闭区间[0, 100]内的整数)组成,每个项目间用1个空格隔开。当读到 N=0 时,全部输入结束,相应的结果不要输出。Output对每个测试用例,首先输出1行“Case i:”,其中 i 是测试用例的编号(从1开始)。随后在 N 行中输出按要求排序后的结果,即:当 C=1 时,按学号递增排序;当 C=2时,按姓名的非递减字典序排序;当 C=3时,按成绩的非递减排序。当若干学生具有相同姓名或者相同成绩时,则按他们的学号递增排序。Sample Input1234567891011121314153 1000007 James 85000010 Amy 90000001 Zoe 604 2000007 James 85000010 Amy 90000001 Zoe 60000002 James 984 3000007 James 85000010 Amy 90000001 Zoe 60000002 James 900 0Sample Output1234567891011121314Case 1:000001 Zoe 60000007 James 85000010 Amy 90Case 2:000010 Amy 90000002 James 98000007 James 85000001 Zoe 60Case 3:000001 Zoe 60000007 James 85000002 James 90000010 Amy 90Solve:仔细读题,看清题意在写code:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849#include<bits/stdc++.h>using namespace std;struct node{ string number; string name; int sorce;}stu[100001];bool cmp1(node x, node y){ return x.number < y.number;}bool cmp2(node x, node y){ if(x.name == y.name) return x.number < y.number; return x.name < y.name;}bool cmp3(node x, node y){ if(x.sorce == y.sorce) return x.number < y.number; return x.sorce < y.sorce;}int main(){ int n, c; int t = 1; while(scanf("%d %d",&n, &c)!=EOF) { if(n == 0 && c == 0) break; for(int i = 0; i < n; i ++) { cin >stu[i].number >stu[i].name >stu[i].sorce; } if(c == 1) sort(stu, stu + n, cmp1);// if(c == 1) sort(stu.number.begin(), stu.number.end()); string特定的排序方式 else if(c == 2) sort(stu, stu + n, cmp2); else if(c == 3) sort(stu, stu + n, cmp3); printf("Case %d:\n",t ++); for(int i = 0; i < n; i ++) { cout << stu[i].number << ' ' << stu[i].name<< ' ' << stu[i].sorce << endl; } } return 0;}统计同成绩学生人数Problem Description读入N名学生的成绩,将获得某一给定分数的学生人数输出。Input测试输入包含若干测试用例,每个测试用例的格式为第1行:N第2行:N名学生的成绩,相邻两数字用一个空格间隔。第3行:给定分数当读到N=0时输入结束。其中N不超过1000,成绩分数为(包含)0到100之间的一个整数。Output对每个测试用例,将获得给定分数的学生人数输出。Sample Input12345678910380 60 9060285 660560 75 90 55 75750Sample Output123102Solve:简单题code:123456789101112131415161718192021222324#include<bits/stdc++.h>using namespace std;int main(){ int n, m; int a[1001]; while(scanf("%d",&n)!=EOF) { int ans = 0; if(n == 0) break; for(int i = 0; i < n; i ++) { cin >a[i]; } cin >m; for(int i = 0; i < n ; i ++) { if(a[i] == m) ans ++; } cout << ans << endl; } return 0;}What Is Your Grade?Problem Description“Point, point, life of student!”This is a ballad(歌谣)well known in colleges, and you must care about your score in this exam too. How many points can you get? Now, I told you the rules which are used in this course.There are 5 problems in this final exam. And I will give you 100 points if you can solve all 5 problems; of course, it is fairly difficulty for many of you. If you can solve 4 problems, you can also get a high score 95 or 90 (you can get the former(前者) only when your rank is in the first half of all students who solve 4 problems). Analogically(以此类推), you can get 85、80、75、70、65、60. But you will not pass this exam if you solve nothing problem, and I will mark your score with 50.Note, only 1 student will get the score 95 when 3 students have solved 4 problems.I wish you all can pass the exam!Come on!InputInput contains multiple test cases. Each test case contains an integer N (1<=N<=100, the number of students) in a line first, and then N lines follow. Each line contains P (0<=P<=5 number of problems that have been solved) and T(consumed time). You can assume that all data are different when 0<p.A test case starting with a negative integer terminates the input and this test case should not to be processed.OutputOutput the scores of N students in N lines for each case, and there is a blank line after each case.Sample Input1234567845 06:30:174 07:31:274 08:12:124 05:23:1315 06:30:17-1Sample Output123456100909095100Solve:仔细理解题意,认真写code:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110//第一种//#include <iostream>//#include<cstdio>//#include<cstring>//#include<algorithm>//using namespace std;//struct node//{// int x;// char s[10];//}a[101];//int main()//{// int n;// while(scanf("%d",&n),n!=-1)// {// for(int i=0;i<n;i++)// scanf("%d %s",&a[i].x,a[i].s);// int t[5]={0};// for(int i=4;i>0;i--)//做出相同题数的人的个数// {// for(int j=0;j<n;j++)// {// if(a[j].x==i) t[i]++;// }// }// for(int i=0;i<n;i++)// {// if(a[i].x==5) printf("100\n");// else if (a[i].x==0) printf("50\n");// else// {// int k=0;// for(int j=0;j<n;j++)// {// if(a[j].x==a[i].x&&strcmp(a[j].s,a[i].s)<0)////头文件是string,实质就是a[j].s<a[i].s// k++;// }// if(k>=t[a[i].x]/2)////相同题数用时短的人数做出相同题数的总人数一半// printf("%d\n",100-(5-a[i].x)*10);// else// printf("%d\n",100-(5-a[i].x)*10+5);// }// }// printf("\n");// }// return 0;//}//第二种#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;struct ssq{ int x; char t[20]; int fs;}sq[1005];int main(){ int n; while(~scanf("%d",&n)&&n>0) { int s[10],ss[10]; memset(s,0,sizeof(s)); memset(ss,0,sizeof(ss)); for(int i=0;i<n;i++) { scanf("%d %s",&sq[i].x,sq[i].t); s[sq[i].x]++;//记录做完题数对应数量人数 sq[i].fs=0;//分数归0 } for(int i=0;i<n;i++)//遍历结构体 { if(sq[i].x==5)//特殊处理5题 sq[i].fs=100; else if(sq[i].x==0)//特殊处理0题 sq[i].fs=50; else { if(s[sq[i].x]==1)//特殊处理做对1题 sq[i].fs=(sq[i].x*10+55); else if(ss[sq[i].x]<s[sq[i].x]/2&&sq[i].fs==0)//找出本题数中最小耗时 { int v=i;//记录位置当前 for(int j=0;j<n;j++) { if(sq[j].fs==0&&sq[j].x==sq[v].x&&strcmp(sq[j].t,sq[v].t)<0)//更改最小耗时位置 v=j; } ss[sq[i].x]++;//记录已经找出的最小耗时人数 sq[v].fs=55+sq[v].x*10;//更改分数 } } } for(int i=0;i<n;i++) { if(sq[i].fs!=0) printf("%d\n",sq[i].fs); else printf("%d\n",sq[i].x*10+50);//没有分值的赋基础分值 } printf("\n"); } return 0;}Magical BamboosProblem DescriptionIn a magical forest, there exists N bamboos that don’t quite get cut down the way you would expect.Originally, the height of the ith bamboo is equal to hi. In one move, you can push down a bamboo and decrease its height by one, but this move magically causes all the other bamboos to increase in height by one.If you can do as many moves as you like, is it possible to make all the bamboos have the same height?InputThe first line of input is T – the number of test cases.The first line of each test case contains an integer N (1 ≤ N ≤ 105) - the number of bamboos.The second line contains N space-separated integers hi (1 ≤ hi ≤ 105) - the original heights of the bamboos.OutputFor each test case, output on a single line “yes” (without quotes), if you can make all the bamboos have the same height, and “no” otherwise.Input12345232 4 221 2Output12yesnoSolve:找规律code:1234567891011121314151617181920212223242526272829#include<bits/stdc++.h>using namespace std;int a[1000007];int main(){ int n, m; scanf("%d",&n); while(n --) { scanf("%d",&m); int t = 0; for(int i = 0; i < m; i ++) { scanf("%d",&a[i]); } for(int i = 0; i < m - 1; i ++) { if((a[i + 1] - a[i]) % 2 != 0) { t = 1; break; } } if(t == 1) printf("no\n"); else printf("yes\n"); } return 0;}Bear and Three BallsProblem DescriptionLimak is a little polar bear. He has n balls, the i-th ball has size ti.Limak wants to give one ball to each of his three friends. Giving gifts isn’t easy — there are two rules Limak must obey to make friends happy:No two friends can get balls of the same size.No two friends can get balls of sizes that differ by more than 2.For example, Limak can choose balls with sizes 4, 5 and 3, or balls with sizes 90, 91 and 92. But he can’t choose balls with sizes 5, 5 and 6 (two friends would get balls of the same size), and he can’t choose balls with sizes 30, 31 and 33 (because sizes 30 and 33 differ by more than 2).Your task is to check whether Limak can choose three balls that satisfy conditions above.InputThe first line of the input contains one integer n (3 ≤ n ≤ 50) — the number of balls Limak has.The second line contains n integers t1, t2, …, tn (1 ≤ ti ≤ 1000) where ti denotes the size of the i-th ball.OutputPrint “YES” (without quotes) if Limak can choose three balls of distinct sizes, such that any two of them differ by no more than 2. Otherwise, print “NO” (without quotes).Examples123456789101112131415Input418 55 16 17OutputYESInput640 41 43 44 44 44OutputNOInput85 972 3 4 1 4 970 971OutputYES123456NoteIn the first sample, there are 4 balls and Limak is able to choose three of them to satisfy the rules. He must must choose balls with sizes 18, 16 and 17.In the second sample, there is no way to give gifts to three friends without breaking the rules.In the third sample, there is even more than one way to choose balls:Choose balls with sizes 3, 4 and 5.Choose balls with sizes 972, 970, 971.Solve:找规律code:123456789101112131415161718192021222324252627282930#include<bits/stdc++.h>using namespace std;int main(){ int n; int a[100001], b[100001]; while(scanf("%d",&n)!=EOF) { int ans = 0; int t = 1; for(int i = 0; i < n; i ++) { cin >a[i]; } sort(a, a + n); for(int i = 0; i < n; i ++) { if(binary_search(a, a + n, a[i] + 1) && binary_search(a, a + n, a[i] + 2)) { ans = 1; break; } } if(ans == 1) cout << "YES" << endl; else cout << "NO" << endl; } return 0;}今年暑假不ACProblem Description12345678“今年暑假不AC?”“是的。”“那你干什么呢?”“看世界杯呀,笨蛋!”“@#$%^&*%...”确实如此,世界杯来了,球迷的节日也来了,估计很多ACMer也会抛开电脑,奔向电视了。作为球迷,一定想看尽量多的完整的比赛,当然,作为新时代的好青年,你一定还会看一些其它的节目,比如新闻联播(永远不要忘记关心国家大事)、非常6+7、超级女生,以及王小丫的《开心辞典》等等,假设你已经知道了所有你喜欢看的电视节目的转播时间表,你会合理安排吗?(目标是能看尽量多的完整节目)Input输入数据包含多个测试实例,每个测试实例的第一行只有一个整数n(n<=100),表示你喜欢看的节目的总数,然后是n行数据,每行包括两个数据Ti_s,Ti_e (1<=i<=n),分别表示第i个节目的开始和结束时间,为了简化问题,每个时间都用一个正整数表示。n=0表示输入结束,不做处理。Output对于每个测试实例,输出能完整看到的电视节目的个数,每个测试实例的输出占一行。1234567891011121314151617Sample Input121 33 40 73 815 1915 2010 158 186 125 104 142 90Sample Output5Solve:头尾对接code:1234567891011121314151617181920212223242526272829303132333435363738#include<bits/stdc++.h>using namespace std;struct node{ int start, end;}g[101];int cmp(node x, node y){ return x.end < y.end;}int main(){ int n; while(scanf("%d",&n)!=EOF) { if(n == 0) break; int ans = 1; for(int i = 0; i < n; i ++) { cin >g[i].start >g[i].end; } sort(g, g + n, cmp); int s = g[0].end; for(int i = 1;i < n; i ++) { if(g[i].start >= s) { ans ++; s = g[i].end; } } cout << ans << endl; } return 0;}The sum problemProblem DescriptionGiven a sequence 1,2,3,……N, your job is to calculate all the possible sub-sequences that the sum of the sub-sequence is M.InputInput contains multiple test cases. each case contains two integers N, M( 1 <= N, M <= 1000000000).input ends with N = M = 0.OutputFor each test case, print all the possible sub-sequence that its sum is M.The format is show in the sample below.print a blank line after each test case.123456789101112Sample Input20 1050 300 0Sample Output[1,4][10,10][4,8][6,9][9,11][30,30]Solve:找规律,数学思维code:1234567891011121314151617181920212223#include<bits/stdc++.h>using namespace std;int main(){ int n, m; while(scanf("%d %d",&n, &m)!=EOF) { if(n == 0 && m == 0) break; for(int i = sqrt(2 * m); i >= 1; i --) { //s = a1 * i + i * (i - 1) / 2; int a1 = (m - i * (i - 1) / 2) / i; if((a1 * i) + i * (i - 1) / 2 == m) printf("[%d,%d]\n",a1, a1 + i - 1); } puts(""); } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>集训</category>
</categories>
<tags>
<tag>ACM</tag>
<tag>Algorithm</tag>
<tag>算法集训</tag>
</tags>
</entry>
<entry>
<title><![CDATA[资源收集]]></title>
<url>%2F2019%2F07%2F15%2F%E8%B5%84%E6%BA%90%E6%94%B6%E9%9B%86%2F</url>
<content type="text"><![CDATA[特别说明写下这个页面的目的只是为了提供一些好的资源以供今后的学习做一些铺垫~~~以后将会持续更新发张好看的图片镇楼!!优化网站:https://blog.csdn.net/qq_36759224/article/details/85420403#font_colorFF0000___font_129大佬博客链接https://www.itrhx.com/深度优化博客点击这里将自己做的的网页发布到github托管传送门上传文件到coding上面传送门将文件上传到github先点击上传就是那个Upload files然后直接拖拽进去就行了学习前端网站传送门]]></content>
<categories>
<category>资源</category>
<category>知识点的资源</category>
</categories>
<tags>
<tag>学习</tag>
<tag>资源</tag>
</tags>
</entry>
<entry>
<title><![CDATA[添加板娘、一言]]></title>
<url>%2F2019%2F07%2F14%2F%E6%9D%BF%E5%A8%98%E6%95%99%E7%A8%8B%2F</url>
<content type="text"><![CDATA[添加板娘、一言好看的动漫人物更能添加博客的观赏性加一个试试??添加板娘好看的板娘肯定能增加博客的美观度“静态板娘”hexo的官方是支持看板娘的,已经封装好了插件,但只是模型,不能说话、不能换装、功能较少。安装模块npm install --save hexo-helper-live2d输入以下命令,下载相应的模型,将 packagename 更换成模型名称即可,更多模型选择请点击此处,各个模型的预览请点击此处npm install packagename在 站点配置文件 或 主题配置文件 中的 _config.yml 文件添加如下内容:12345678910111213# Live2D## https://github.com/EYHN/hexo-helper-live2dlive2d:enable: truescriptFrom: localmodel: use: live2d-widget-model-haruto #模型选择display: position: right #模型位置 width: 150 #模型宽度 height: 300 #模型高度mobile: show: false #是否在手机端显示三连一下就OK了动态板娘大神作品,功能齐全。能说话、能换装、能玩游戏、能拍照、还能自定义。下载巨佬的项目,解压到本地博客目录的themes/next/source下,修改autoload.js文件,如下:把1const live2d_path = "https://cdn.jsdelivr.net/gh/stevenjoezhang/live2d-widget/";改成1const live2d_path = "/live2d-widget/";在/themes/next/layout/_layout.swing中,新增如下内容:1<script src="/live2d-widget/autoload.js"></script>在 主题配置文件 中,新增如下内容:12live2d: enable: true想自己魔改的想修改看板娘大小、位置、格式、文本内容等,可查看并修改 waifu-tips.js 、 waifu-tips.json 和 waifu.css为您的Hexo博客添加Hitokoto一言功能有时候,仅仅是一句简单的话就能够给予我们很大的动力而一言就是这样的一个接口/平台加一个试试??链接]]></content>
<categories>
<category>资源</category>
<category>教程</category>
</categories>
<tags>
<tag>学习</tag>
<tag>资源</tag>
<tag>兴趣</tag>
<tag>教程</tag>
</tags>
</entry>
<entry>
<title><![CDATA[MySQL简介]]></title>
<url>%2F2019%2F07%2F12%2FMySQL%2F</url>
<content type="text"><![CDATA[什么是数据库??数据库(Database)是按照数据结构来组织、存储和管理数据的仓库。1234每个数据库都有一个或多个不同的 API 用于创建,访问,管理,搜索和复制所保存的数据。我们也可以将数据存储在文件中,但是在文件中读写数据速度相对较慢。所以,现在我们使用关系型数据库管理系统(RDBMS)来存储和管理的大数据量。所谓的关系型数据库,是建立在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据。RDBMS 即关系数据库管理系统(Relational Database Management System)的特点:1.数据以表格的形式出现2.每行为各种记录名称3.每列为记录名称所对应的数据域4.许多的行和列组成一张表单5.若干的表单组成databaseRDBMS术语12345678910数据库: 数据库是一些关联表的集合。数据表: 表是数据的矩阵。在一个数据库中的表看起来像一个简单的电子表格。列: 一列(数据元素) 包含了相同的数据, 例如邮政编码的数据。行:一行(=元组,或记录)是一组相关的数据,例如一条用户订阅的数据。冗余:存储两倍数据,冗余降低了性能,但提高了数据的安全性。主键:主键是唯一的。一个数据表中只能包含一个主键。你可以使用主键来查询数据。外键:外键用于关联两个表。复合键:复合键(组合键)将多个列作为一个索引键,一般用于复合索引。索引:使用索引可快速访问数据库表中的特定信息。索引是对数据库表中一列或多列的值进行排序的一种结构。类似于书籍的目录。参照完整性: 参照的完整性要求关系中不允许引用不存在的实体。与实体完整性是关系模型必须满足的完整性约束条件,目的是保证数据的一致性。基础知识12345表头(header): 每一列的名称;列(col): 具有相同数据类型的数据的集合;行(row): 每一行用来描述某条记录的具体信息;值(value): 行的具体信息, 每个值必须与该列的数据类型相同;键(key): 键的值在当前列中具有唯一性。MySQL简介MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 公司。MySQL 是一种关联数据库管理系统,关联数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。相关内容:1234567MySQL 是开源的,所以你不需要支付额外的费用。MySQL 支持大型的数据库。可以处理拥有上千万条记录的大型数据库。MySQL 使用标准的 SQL 数据语言形式。MySQL 可以运行于多个系统上,并且支持多种语言。这些编程语言包括 C、C++、Python、Java、Perl、PHP、Eiffel、Ruby 和 Tcl 等。MySQL 对PHP有很好的支持,PHP 是目前最流行的 Web 开发语言。MySQL 支持大型数据库,支持 5000 万条记录的数据仓库,32 位系统表文件最大可支持 4GB,64 位系统支持最大的表文件为8TB。MySQL 是可以定制的,采用了 GPL 协议,你可以修改源码来开发自己的 MySQL 系统。]]></content>
<categories>
<category>数据库</category>
<category>MySQL</category>
</categories>
<tags>
<tag>兴趣</tag>
<tag>教程</tag>
<tag>MySQL</tag>
<tag>数据库</tag>
</tags>
</entry>
<entry>
<title><![CDATA[request]]></title>
<url>%2F2019%2F07%2F06%2Frequest%2F</url>
<content type="text"><![CDATA[前提摘要想写下这一篇的原因还是起源于在网上下载图片的时候一张一张下载的太慢而且麻烦,所以就想着写一个东西, 能够快速批量下载。于是,就有了爬虫的想法,当然,以我现有水平只能够用request去爬取,爬虫的相关内容会在以后慢慢更新的一句话,我用爬虫就是用来下载资源的~后面会更新相关内容来完善。。。。注意:以下内容都是以python3为基础实现简单介绍网络爬虫是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。 服务器的交互方式http中与服务器定义的几种基本交互方式,get、post、delete、put、head和options。get请求常用于查询获取资源信息,常见表现形式url传递参数数据, 以?开始&分隔参数值。post请求向服务器提交数据。put请求向服务器端发送信息修改数据。delete请求向服务器发送信息删除数据。基础先要了解request是一个模块,在python中就是一个库,用来抓取网上资源的 下载requests模块 若是安装过python3,则命令端输入`pip install requests`即可 用法先导入`requests`模块(这个模块名称为requests)只不过平时都说是request了,这一点不能弄错 import requests 与请求网址交互 1234requests.get("url")requests.post("url")requests.put("url")request.delete("url") 说一下常用的GET请求: 两种方法: 1.直接传: 例如:requests.get("http://www.baidu.com") 2.间接传: 例如:url = "http://www.baidu.com" requests.get(url=url) 间接传的好处是可以添加其他参数 常用属性和方法1234567url #打印返回地址text #以文本方式返回html源码content #以字节流返回html源码cookies #返回cookies信息status_code #打印状态码headers #返回html头信息encoding #处理字符集get请求回复对象所包含的属性:12345678resp = requests.get()resp.text 获取网站源码(字符串类型)resp.encoding 访问或定制编码方式,如一般所得网页源码出现乱码的情况下可以设置:resp.encoding='gb2312'resp.url 获取请求的urlresp.content 获取网站源码,但响应的是字节类型resp.status_code 响应的状态码resp.headers 响应的头信息resp.json() 获取json数据]]></content>
<categories>
<category>Python</category>
<category>爬虫</category>
</categories>
<tags>
<tag>兴趣</tag>
<tag>教程</tag>
<tag>Python</tag>
<tag>爬虫</tag>
</tags>
</entry>
<entry>
<title><![CDATA[优美文章]]></title>
<url>%2F2019%2F07%2F04%2F%E4%BC%98%E7%BE%8E%E6%96%87%E7%AB%A0%2F</url>
<content type="text"><![CDATA[摘要每一个人都不是超人,都不可能会有无穷的精力,但还是需要我们努力的奔跑!基于此,于考试的紧张期间写下一些感悟文章来反思自己,生活不需要一致的工作和学习,偶尔也需要一些放松。活在当下,立足当下,去努力,去超越。这个世界很大,你不打算去看看嘛?最后,奉上座右铭:我并不想着去超越谁,只是想比昨天的自己强一点点······以下内容从网上摘抄而来,并非自己写的。你的人品,决定你的前途文/李思圆1 我在老家有两个朋友老王和老张。老王5年前跟老张借了5万块,说是做装修生意急用,并承诺两年内还清。老张二话没说,把钱借给了老王。出于信任,也没让他写借条。但两年后,老王只字不提还钱的事,倒是全款买了一辆新车。 老张问他要钱,老王推三阻四。一会儿说有事不在家,一会儿电话又打不通,甚至故意玩消失。最终两家人闹掰了,老张没要回钱,吃了一个哑巴亏。村里人都知道这件事,虽然大家嘴上没说,但心里都觉得老王不厚道。又过了两年,村里上百户人搬迁,都需要装修新房。老王心想,乡亲们一定会找他。可奇怪的是,即便他的报价低了很多,许多村民也不买账。原来,他的坏口碑一传十,十传百,没过几年,装修生意彻底做不下去了。有时候,一个人或许可以靠不讲信用获取一些暂时的利益,但那绝不是正道。想要站得稳,走得远,笑到最后,还得靠人品做支撑。2前些日子我朋友的公司搞竞聘,有个工作能力非常强的男同事落选了。后来男同事得知,他是被总经理撤下来了。总经理对他说:小伙子,既要学会做事,更要学会做人。后来这个男同事负气辞职,总经理才道出真相。原来有次这个男同事坐电梯时,一个外卖小哥背着一个很重的外卖包,风尘仆仆地想进来。电梯里是有空间的,只要这个男同事往后退几步就行,但他就是故意不让。一边快速按关门键,一边说,几步路而已,也要坐电梯。这件事被总经理知道了,就把他拉入了黑名单。一个学不会尊重别人的人,心性就出了问题。这样的人,谁敢重用?也许一个人的前途,跟自身的智商、实力和运气等有关,可拼到最后,人品才是最终的把关口。3曾听一位读者说起,他曾供职的私企因经营不善大规模裁员。当时许多被裁的员工闹情绪,有人故意销毁重要文件,有人把客户的联络方式偷偷拷贝走,还有人四处造谣说老板的坏话。这位读者丢了工作也不开心。但在最后一个月,他对工作依然没有敷衍了事。在交接工作时,他还把需要特别注意的事项一一罗列出来。老板被他的所作所为感动,通过熟人把他介绍到另外一家公司工作。这位读者因为踏实肯干,很快就走上了管理岗位,薪水待遇也提高很多。人品就是一个人的根基。为人善良、懂得体谅、不去做小人之事,这样的人,会格外得到好运的眷顾、贵人的扶持和机会的偏爱。4有人说,能力和学历才是好工作的敲门砖,情商和智商才是好职位的守护神。但其实无论在哪行哪业,都不缺高手。前途一片光明的人,一定不是颠倒黑白、动歪脑筋的人,而是那些在同等条件下,人品过关的人。也许你反应快、人脉广、办法多,但这些也只是你的加分项。为人诚实,待人和善,有底线有原则,不做有损他人的事,这些却是你的必选项。一个人能力差一点,灵性少一点,实力欠一点,都可以花时间和精力慢慢去补足,但人品差却是致命的缺陷。好人品,是做人的良心,是为人的修养。没有了好人品,其他都免谈。一个人走得远不远、久不久、稳不稳,人品才是最关键的因素。小结学会做人,学会做事,掌握好人生的必选项,添加加分项,我们会更好的适应这个世界]]></content>
<categories>
<category>总结</category>
<category>想法</category>
</categories>
<tags>
<tag>想法</tag>
</tags>
</entry>
<entry>
<title><![CDATA[map与vector的用法]]></title>
<url>%2F2019%2F07%2F02%2Fmap%E4%B8%8Evector%E7%9A%84%E7%94%A8%E6%B3%95%2F</url>
<content type="text"><![CDATA[vector向量 相当于一个数组在内存中分配一块连续的内存空间进行存储。支持不指定vector大小的存储。STL内部实现时,首先分配一个非常大的内存空间预备进行存储,即capacituy()函数返回的大小,当超过此分配的空间时再整体重新放分配一块内存存储,这给人以vector可以不指定vector即一个连续内存的大小的感觉。通常此默认的内存分配能完成大部分情况下的存储。map映照容器的元素数据是一个键值和一个映照数据组成的,键值与映照数据之间具有一一映照的关系。map映照容器的数据结构是采用红黑树来实现的,插入键值的元素不允许重复,比较函数只对元素的键值进行比较,元素的各项数据可通过键值检索出来。使用map容器需要头文件包含语句“#include”,map文件也包含了对multimap多重映照容器的定义。mapMap是c++的一个标准容器,它提供了很好一对一的关系,在一些程序中建立一个map可以起到事半功倍的效果,总结了一些map基本简单实用的操作!map最基本的构造函数;123map<string , int >mapstring; map<int ,string >mapint;map<sring, char>mapstring; map< char ,string>mapchar;map<char ,int>mapchar; map<int ,char >mapint;map添加数据;1234map<int ,string> maplive; 1.maplive.insert(pair<int,string>(102,"aclive"));2.maplive.insert(map<int,string>::value_type(321,"hai"));3, maplive[112]="April";//map中最简单最常用的插入添加!map中元素的查找:123456find()函数返回一个迭代器指向键值为key的元素,如果没找到就返回指向map尾部的迭代器。 map<int ,string >::iterator l_it;; l_it=maplive.find(112);if(l_it==maplive.end()) cout<<"we do not find 112"<<endl;else cout<<"wo find 112"<<endl;map中元素的删除:123456如果删除112;map<int ,string >::iterator l_it;;l_it=maplive.find(112);if(l_it==maplive.end()) cout<<"we do not find 112"<<endl;else maplive.erase(l_it); //delete 112;map中 swap的用法:12345678910111213141516171819202122232425262728293031323334353637 Map中的swap不是一个容器中的元素交换,而是两个容器交换; For example: #include <map> #include <iostream> using namespace std; int main( ) { map <int, int> m1, m2, m3; map <int, int>::iterator m1_Iter; m1.insert ( pair <int, int> ( 1, 10 ) ); m1.insert ( pair <int, int> ( 2, 20 ) ); m1.insert ( pair <int, int> ( 3, 30 ) ); m2.insert ( pair <int, int> ( 10, 100 ) ); m2.insert ( pair <int, int> ( 20, 200 ) ); m3.insert ( pair <int, int> ( 30, 300 ) ); cout << "The original map m1 is:"; for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ ) cout << " " << m1_Iter->second; cout << "." << endl; // This is the member function version of swap //m2 is said to be the argument map; m1 the target map m1.swap( m2 ); cout << "After swapping with m2, map m1 is:"; for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ ) cout << " " << m1_Iter -> second; cout << "." << endl; cout << "After swapping with m2, map m2 is:"; for ( m1_Iter = m2.begin( ); m1_Iter != m2.end( ); m1_Iter++ ) cout << " " << m1_Iter -> second; cout << "." << endl; // This is the specialized template version of swap swap( m1, m3 ); cout << "After swapping with m3, map m1 is:"; for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ ) cout << " " << m1_Iter -> second; cout << "." << endl;}map的sort问题:123456789101112131415161718192021222324252627 Map中的元素是自动按key升序排序,所以不能对map用sort函数: For example: #include <map> #include <iostream> using namespace std; int main( ) { map <int, int> m1; map <int, int>::iterator m1_Iter; m1.insert ( pair <int, int> ( 1, 20 ) ); m1.insert ( pair <int, int> ( 4, 40 ) ); m1.insert ( pair <int, int> ( 3, 60 ) ); m1.insert ( pair <int, int> ( 2, 50 ) ); m1.insert ( pair <int, int> ( 6, 40 ) ); m1.insert ( pair <int, int> ( 7, 30 ) ); cout << "The original map m1 is:"<<endl; for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ ) cout << m1_Iter->first<<" "<<m1_Iter->second<<endl; } The original map m1 is: 1 20 2 50 3 60 4 40 6 40 7 30map的基本操作函数:1234567891011121314151617181920C++ Maps是一种关联式容器,包含“关键字/值”对begin() 返回指向map头部的迭代器clear() 删除所有元素count() 返回指定元素出现的次数empty() 如果map为空则返回trueend() 返回指向map末尾的迭代器equal_range() 返回特殊条目的迭代器对erase() 删除一个元素find() 查找一个元素get_allocator() 返回map的配置器insert() 插入元素key_comp() 返回比较元素key的函数lower_bound() 返回键值>=给定元素的第一个位置max_size() 返回可以容纳的最大元素个数rbegin() 返回一个指向map尾部的逆向迭代器rend() 返回一个指向map头部的逆向迭代器size() 返回map中元素的个数swap() 交换两个mapupper_bound() 返回键值>给定元素的第一个位置value_comp() 返回比较元素value的函数总结:优点:(1) 不指定一块内存大小的数组的连续存储,即可以像数组一样操作,但可以对此数组进行动态操作。通常体现在push_back() pop_back()(2) 随机访问方便,即支持[ ]操作符和vector.at()(3) 节省空间。缺点:(1) 在内部进行插入删除操作效率低。(2) 只能在vector的最后进行push和pop,不能在vector的头进行push和pop。(3) 当动态添加的数据超过vector默认分配的大小时要进行整体的重新分配、拷贝与释放vector标准库Vector类型使用需要的头文件:#includeVector:Vector 是一个类模板。不是一种数据类型。 Vector是一种数据类型。定义和初始化Vectorv1; //默认构造函数v1为空Vectorv2(v1);//v2是v1的一个副本Vectorv3(n,i);//v3包含n个值为i的元素Vectorv4(n); //v4含有n个值为0的元素值初始化1> 如果没有指定元素初始化式,标准库自行提供一个初始化值进行值初始化。2> 如果保存的式含有构造函数的类类型的元素,标准库使用该类型的构造函数初始化。3> 如果保存的式没有构造函数的类类型的元素,标准库产生一个带初始值的对象,使用这个对象进行值初始化。Vector对象最重要的几种操作v.push_back(t) 在数组的最后添加一个值为t的数据v.size() 当前使用数据的大小v.empty() 判断vector是否为空v[n] 返回v中位置为n的元素v1=v2 把v1的元素替换为v2元素的副本v1==v2 判断v1与v2是否相等!=、<、<=、>、>= 保持这些操作符惯有含义vector容器类型vector容器是一个模板类,可以存放任何类型的对象(但必须是同一类对象)。vector对象可以在运行时高效地添加元素,并且vector中元素是连续存储的。vector的构造函数原型:templateexplicit vector(); // 默认构造函数,vector对象为空explicit vector(size_type n, const T& v = T()); // 创建有n个元素的vector对象vector(const vector& x);vector(const_iterator first, const_iterator last);注:vector容器内存放的所有对象都是经过初始化的。如果没有指定存储对象的初始值,那么对于内置类型将用0初始化,对于类类型将调用其默认构造函数进行初始化(如果有其它构造函数而没有默认构造函数,那么此时必须提供元素初始值才能放入容器中)。举例:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849vector<string> v1; // 创建空容器,其对象类型为string类vector<string> v2(10); // 创建有10个具有初始值(即空串)的string类对象的容器vector<string> v3(5, "hello"); // 创建有5个值为“hello”的string类对象的容器vector<string> v4(v3.begin(), v3.end()); // v4是与v3相同的容器(完全复制)vector的操作(下面的函数都是成员函数)bool empty() const; // 如果为容器为空,返回true;否则返回falsesize_type max_size() const; // 返回容器能容纳的最大元素个数size_type size() const; // 返回容器中元素个数size_type capacity() const; // 容器能够存储的元素个数,有:capacity() >= size()void reserve(size_type n); // 确保capacity() >= nvoid resize(size_type n, T x = T()); // 确保返回后,有:size() == n;如果之前size()<n,那么用元素x的值补全。reference front(); // 返回容器中第一个元素的引用(容器必须非空)const_reference front() const;reference back(); // 返回容器中最后一个元素的引用(容器必须非空)const_reference back() const;reference operator[](size_type pos); // 返回下标为pos的元素的引用(下标从0开始;如果下标不正确,则属于未定义行为。const_reference operator[](size_type pos) const;reference at(size_type pos); // 返回下标为pos的元素的引用;如果下标不正确,则抛出异常out_of_rangeconst_reference at(size_type pos) const;void push_back(const T& x); // 向容器末尾添加一个元素void pop_back(); // 弹出容器中最后一个元素(容器必须非空)// 注:下面的插入和删除操作将发生元素的移动(为了保持连续存储的性质),所以之前的迭代器可能失效iterator insert(iterator it, const T& x = T()); // 在插入点元素之前插入元素(或者说在插入点插入元素)void insert(iterator it, size_type n, const T& x); // 注意迭代器可能不再有效(可能重新分配空间)void insert(iterator it, const_iterator first, const_iterator last);iterator erase(iterator it); // 删除指定元素,并返回删除元素后一个元素的位置(如果无元素,返回end())iterator erase(iterator first, iterator last); // 注意:删除元素后,删除点之后的元素对应的迭代器不再有效。void clear() const; // 清空容器,相当于调用erase( begin(), end())void assign(size_type n, const T& x = T()); // 赋值,用指定元素序列替换容器内所有元素void assign(const_iterator first, const_iterator last);const_iterator begin() const; // 迭代序列iterator begin();const_iterator end() const;iterator end();const_reverse_iterator rbegin() const;reverse_iterator rbegin();const_reverse_iterator rend() const;reverse_iterator rend();vector对象的比较(非成员函数)针对vector对象的比较有六个比较运算符:operator==、operator!=、operator<、operator<=、operator>、operator>=。其中,对于operator==和operator!=,如果vector对象拥有相同的元素个数,并且对应位置的元素全部相等,则两个vector对象相等;否则不等。对于operator<、operator<=、operator>、operator>=,采用字典排序策略比较。注:其实只需要实现operator==和operator!=就可以了,其它可以根据这两个实现。因为,operator!= (lhs, rhs) 就是 !(lhs == rhs),operator<=(lhs, rhs) 就是 !(rhs < lhs),operator>(lhs, rhs) 就是 (rhs < lhs),operator>=(lhs, rhs) 就是 !(lhs, rhs)。vector类的迭代器vector类的迭代器除了支持通用的前缀自增运算符外,还支持算术运算:it + n、it - n、it2 - it1。注意it2 - it1返回值为difference_type(signed类型)。注意,任何改变容器大小的操作都可能造成以前的迭代器失效。应用示例1234567891011121314151617181920212223242526272829303132#include <iostream>#include <cassert>#include <vector>using namespace std;int main(){ vector<string> v(5, "hello"); vector<string> v2(v.begin(), v.end()); assert(v == v2); cout<<"> Before operation"<<endl; for(vector<string>::const_iterator it = v.begin(); it < v.end(); ++it) cout<<*it<<endl; v.insert(v.begin() + 3, 4, "hello, world"); cout<<"> After insert"<<endl; for(vector<string>::size_type i = 0; i < v.size(); ++i) cout<<v[i]<<endl; vector<string>::iterator it = v.erase(v.begin() + 3, v.begin() + 6); assert(*it == "hello, world"); cout<<"> After erase"<<endl; for(vector<string>::size_type i = 0; i != v.size(); ++i) cout<<v[i]<<endl; assert(v.begin() + v.size() == v.end()); assert(v.end() - v.size() == v.begin()); assert(v.begin() - v.end() == -vector<string>::difference_type(v.size()));return 0;}程序说明:上面程序中用了三个循环输出容器中的元素,每个循环的遍历方式是不一样的。特别需要说明的是,第二个循环在条件判断中使用了size() 函数,而不是在循环之前先保存在变量中再使用。之所以这样做,有两个原因:其一,如果将来在修改程序时,在循环中修改了容器元素个数,这个循环仍然能很好地工作,而如果先保存size()函数值就不正确了;其二,由于这些小函数(其实现只需要一条返回语句)基本上都被声明为inline,所以不需要考虑效率问题。c++编程语言中有一种叫做Vector的应用方法,它的作用在实际编程中是非常重要的。下面简单介绍一下C++ Vector的相关应用技巧及基本内容。基本用法(1)vector< 类型 > 标识符 ;(2)vector< 类型 > 标识符(最大容量) ;(3)vector< 类型 > 标识符(最大容量,初始所有值);(4) int i[4] = {12,3,4,5};vector< 类型 > vi(i , i+2); //得到i索引值为3以后的值 ;(5)vector< vector> //vi 定义2维的容器;记得一定要有空格,不然会报错vector< int > line// 在使用的时候一定要首先将vi个行进行初始化;for(int i = 0 ; i < 10 ; i ++){vector.push_back(line);}/// 个人认为使用vector定义二维数组很好,因为是长度可以不预先确定。(6)C++ Vector排序123456vector< int > vi ;vi.push_back(1);vi.push_back(3);vi.push_back(0);sort(vi.begin() , vi.end()); /// /小到大reverse(vi.begin(),vi.end()) /// 从大道小(7)顺序访问1234567891011121314vector < int > vi ;for( int i = 0 ; i < 10 ; i ++){ vector.push_back(i);}for(int i = 0 ; i < 10 ; i ++) /// 第一种调用方法{ cout <<vector[i] <<" " ;}for(vector<int>::iterator it = vi.begin() ; it !=vi.end() ; it++; ///第二种调用方法{ cout << *it << " " ;}(8)寻找1234567vector < int > vi ;for( int i = 0 ; i < 10 ; i ++){ vector.push_back(i);} vector < int >::interator it = find(vi.begin() , vi.end,3) ; cout << *it << endl ; ///返回容器内找到值的位置。(9)使用数组对C++ Vector进行初始化12345678int i[10] ={1,2,3,4,5,6,7,78,8} ;///第一种vector<int> vi(i+1,i+3); ///从第2个元素到第三个元素for(vector <int>::interator it = vi.begin() ; it != vi.end() ; it++;{ cout << *it <<" " ;}(10) 结构体类型1234567891011121314151617struct temp{ public : string str ; public : int id ;}tmpint main(){ vector <temp> t ; temp w1 ; w1.str = "Hellowor" ; w1.id = 1 ; t.push_back(t1); cout << w1.str << "," <<w1.id <<endl ; return 0 ;}比较]]></content>
<categories>
<category>C++</category>
</categories>
<tags>
<tag>C++</tag>
<tag>Algorithm</tag>
<tag>STL</tag>
</tags>
</entry>
<entry>
<title><![CDATA[二分图]]></title>
<url>%2F2019%2F06%2F29%2F%E4%BA%8C%E5%88%86%E5%9B%BE%2F</url>
<content type="text"><![CDATA[概念介绍:二分图二分图又称作二部图,又称作偶图,是图论中的一种特殊模型顶点集V可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属于这两个互不相交的子集,两个子集内的顶点不相邻。设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(iin A,j in B),则称图G为一个二分图。简单来说,就是顶点集 V 可分割为两个互不相交的子集,且图中每条边依附的两个顶点都分属于这两个互不相交的子集,两个子集内的顶点不相邻。当图中的顶点分为两个集合,使得第一个集合中的所有顶点都与第二个集合中的所有顶点相连时,此时是一特殊的二分图,称为完全二分图。充要条件是:图 G 中至少存在两个点,且图中所有回路的长度均为偶数。匹配在给定一个二分图 G,在 G 的一个子图 M 中,若 M 的边集中的任意两条边都不依附于同一个顶点,则称 M 是一个匹配。简单来说,匹配就是一个二分图中边的集合,其中任意两条边都没有公共顶点。如图,红边就是一个匹配最大匹配给定二分图 G 中的所有匹配,所含匹配边数最多的匹配,称为这个图的最大匹配,选择最大匹配的问题即为图的最大匹配问题如图,红边就是一个最大匹配完全匹配一个匹配中,图中每个顶点都与图中某条边相关联,则称此匹配为完全匹配,即一个图的某个匹配中,所有的顶点都是匹配点,就是一个完全匹配。显然,由于完全匹配的任何一个点都已经匹配,添加一条新的匹配边一定会与已有的匹配边冲突,因此完全匹配一定是最大匹配。但要注意的是,并非每个图都存在完全匹配。简单来说,对于一个二分图,左点集中的每一个点都与右点集的一个点匹配,或者右点集中的每一个点都与左点集的一个点匹配。完美匹配对于一个二分图,左点集与右点集的点数相同,若存在一个匹配,包含左点集、右点集的所有顶点,则称为完美匹配。简单来说,对于一个二分图,左点集中的每一个点都与右点集的一个点匹配,并且右点集中的每一个点都与左点集的一个点匹配。如下图,红线所连接的匹配,不仅是一个完全匹配,还是一个完美匹配最大匹配问题举例来说,如下图所示,若存在某一对男孩和女孩之间存在相连的边,就意味着他们彼此喜欢。是否可能让所有男孩和女孩两两配对,使得每对儿都互相喜欢?这就是完全匹配问题。而最多有多少互相喜欢的男孩/女孩可以配对?这就是最大匹配问题。最优匹配带权二分图的权值最大的完全匹配称为最佳匹配,要注意的是,二分图的最优匹配不一定是二分图的最大权匹配。实质上最优匹配问题就是求边权和最大的最大匹配问题。求解技巧:可以添加一些权值为 0 的边,使得最优匹配和最大权匹配统一起来。交替路从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边…形成的路径叫交替路增广路从一个未匹配点出发,走交替路,如果途径另一个未匹配点(出发的点不算),则这条交替路称为增广路(agumenting path)。例如,图 5 中的一条增广路如图 6 所示(图中的匹配点均用红色标出):增广路有一个重要特点:非匹配边比匹配边多一条。因此,研究增广路的意义是改进匹配。只要把增广路中的匹配边和非匹配边的身份交换即可。由于中间的匹配节点不存在其他相连的匹配边,所以这样做不会破坏匹配的性质。交换后,图中的匹配边数目比原来多了 1 条。其实,如果交替路以非匹配点结束的,那么这条交替路就是一条增广路我们可以通过不停地找增广路来增加匹配中的匹配边和匹配点。找不到增广路时,达到最大匹配(这是增广路定理)。匈牙利算法正是这么做的1.匈牙利算法基本思想:通过寻找增广路,把增广路中的匹配边和非匹配边的身份交换,这样就会多出一条匹配边,直到找不到增广路为止。123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657#include<bits/stdc++.h>#define MAXN 9999using namespace std;int nx,ny;//nx表示二分图左边顶点的个数,ny表示二分图右边顶点的个数int m;//m代表边的条数int cx[MAXN],cy[MAXN];//如果有cx[i]=j,则必有cy[j]=i,说明i点和j点能够匹配int x,y;//x点到y点有边int e[MAXN][MAXN];//邻接矩阵int visited[MAXN];//标记数组,标记的永远是二分图右边的顶点int ret;//最后结果int point(int u)//这个函数的作用是寻找增广路和更新cx,xy数组,如果找到了增广路,函数返回1,找不到,函数返回0。{ for(int v=1;v<=ny;v++)//依次遍历右边的所有顶点 { if(e[u][v]&&!visited[v])//条件一:左边的u顶点和右边的v顶点有连通边,条件二:右边的v顶点在没有被访问过,这两个条件必须同时满足 { visited[v]=1;//将v顶点标记为访问过的 if(cy[v]==-1||point(cy[v]))//条件一:右边的v顶点没有左边对应的匹配的点,条件二:以v顶点在左边的匹配点为起点能够找到一条增广路(如果能够到达条件二,说明v顶点在左边一定有对应的匹配点)。 { cx[u]=v;//更新cx,cy数组 cy[v]=u; return 1; } } } return 0;//如果程序到达了这里,说明对右边所有的顶点都访问完了,没有满足条件的。}int main(){ while (cin>>m>>nx>>ny) { memset(cx,-1,sizeof(cx));//初始化cx,cy数组的值为-1 memset(cy,-1,sizeof(cy)); memset(e,0,sizeof(e));//初始化邻接矩阵 ret=0; while (m--)//输入边的信息和更新邻接矩阵 { cin>>x>>y; e[x][y]=1; } for(int i=1;i<=nx;i++)//对二分图左边的所有顶点进行遍历 { if(cx[i]==-1)//如果左边的i顶点还没有匹配的点,就对i顶点进行匹配 { memset(visited,0,sizeof(visited));//每次进行point时,都要对visited数组进行初始化 ret+=point(i);//point函数传入的参数永远是二分图左边的点 } } cout<<ret<<endl; }}2.KM算法KM算法写的比较好的文章https://www.cnblogs.com/wenruo/p/5264235.htmlhttps://www.cnblogs.com/logosG/p/logos.html?tdsourcetag=s_pcqq_aiomsg123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110#include<algorithm>#include<iostream>#include<limits.h>#include<cstdlib>#include<cstring>#include<cassert>#include<string>#include<cstdio>#include<bitset>#include<vector>#include<cmath>#include<ctime>#include<stack>#include<queue>#include<deque>#include<list>#include<set>#define INT 9654234#define mod 1000000007typedef long long ll;using namespace std;const int MAXN = 305;int N;int ex_gir[MAXN];//每个妹子的期望值int ex_boy[MAXN];//每个男生的期望值bool vis_gir[MAXN];//记录每一轮匹配过的女生bool vis_boy[MAXN];//记录每一轮匹配过的男生 每进行新的一轮,都要重新初始化这两个数组int match[MAXN];//match[i]代表和i男生匹配的女生的编号int slack[MAXN];//slack[i]代表i男生如果要获得女生的芳心,至少需要增加的期待值int love[MAXN][MAXN];//记录每个妹子和男生的好感度bool dfs(int gir)//dfs函数求的是编号为gir的女孩能否匹配到男生,如果能,返回true,否则,返回false{ vis_gir[gir]=true;//标记 for(int i=1;i<=N;i++) { if(vis_boy[i])//我们规定每次匹配对于某个男生只访问一遍,如果先前访问过了,就换个男生 continue ; int gap=ex_gir[gir]+ex_boy[i]-love[gir][i]; if(gap==0)//如果这个条件满足,说明编号为gir女孩和编号为i的男孩可能能够匹配成功 { vis_boy[i]=true;//标记 if(match[i]==-1||dfs(match[i]))//如果这两个条件满足其中一个,说明编号为gir女孩和编号为i的男孩匹配成功 { match[i]=gir; return true; } } else slack[i]=min(slack[i],gap);//如果gap不等于0,说明当前状态编号为gir女孩和编号为i的男孩不可能匹配成功,更新slack[i]。 } return false;}int km(){ memset(match,-1,sizeof(match)); memset(ex_boy,0,sizeof(ex_boy)); for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) ex_gir[i]=max(love[i][j],ex_gir[i]);//初始化ex_gir数组 for(int i=1;i<=N;i++) { fill(slack,slack+N+1,INT); while (1)//这个while循环结束的条件是直到让编号为i的女生找到可以匹配的男生后 { memset(vis_gir,false,sizeof(vis_gir)); memset(vis_boy,false,sizeof(vis_gir)); if(dfs(i))//如果这个条件满足,说明编号为i的女生找到了匹配的男生,换下一个女生,如果这个条件不满足,说明这个女生没有匹配到男生,让这个女生降低期望值后继续匹配 break ; int t=INT; for(int j=1;j<=N;j++)//寻找在这一轮匹配中没有匹配到的男生如果要获得女生芳心所需要增加的期待值的最小值 if(!vis_boy[j]) t=min(t,slack[j]); for(int i=1;i<=N;i++)//让在这一轮匹配中匹配过的女生的期待值减小,匹配过的男生的期待值增加 { if(vis_gir[i]) ex_gir[i]-=t; if(vis_boy[i]) ex_boy[i]+=t; else slack[i]-=t;//因为有些女生的期待值减小了,所以这一轮没有被匹配过的男生得到女生的芳心所需要增加的期待值就变小了,所以slack数组中的相应的值要变小 } } } int res=0;//计算好感和 for(int i=1;i<=N;i++) res+=love[match[i]][i]; return res;}int main(){ cin>>N; for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) cin>>love[i][j]; cout<<km()<<endl;}]]></content>
<categories>
<category>图论</category>
<category>Algorithm</category>
</categories>
<tags>
<tag>Algorithm</tag>
<tag>图论</tag>
</tags>
</entry>
<entry>
<title><![CDATA[xpath语法]]></title>
<url>%2F2019%2F06%2F27%2Fxpath%2F</url>
<content type="text"><![CDATA[xpath基本语法XPath即为XML路径语言,它是一种用来确定XML(标准通用标记语言的子集)文档中某部分位置的语言。XPath基于XML的树状结构,有不同类型的节点,包括元素节点,属性节点和文本节点,提供在数据结构树中找寻节点的能力。起初 XPath 的提出的初衷是将其作为一个通用的、介于XPointer与XSLT间的语法模型。但是 XPath 很快的被开发者采用来当作小型查询语言。简单来说我们通过Xpath可以获取XML中的指定元素和指定节点的值。在网络爬虫中我们通过会把爬虫获取的HTML数据转换成XML结构,然后通过XPath解析,获取我们想要的结果。样例:123456789101112131415<?xml version="1.0" encoding="ISO-8859-1"?><bookstore><book> <title lang="eng">Harry Potter</title> <price>29.99</price></book><book> <title lang="eng">Learning XML</title> <price>39.95</price></book></bookstore>1.选取节点表达式描述nodename选取此节点的所有子节点/从根节点选取//从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置.选取当前节点..选取当前节点的父节点@选取属性2. 路径表达式路径表达式结果bookstore选取 bookstore 元素的所有子节点。/bookstore选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!bookstore/book选取属于 bookstore 的子元素的所有 book 元素。//book选取所有 book 子元素,而不管它们在文档中的位置。bookstore//book选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。//@lang选取名为 lang 的所有属性。3.谓词(Predicates)谓语用来查找某个特定的节点或者包含某个指定的值的节点。谓语被嵌在方括号中。路径表达式结果/bookstore/book[1]选取属于 bookstore 子元素的第一个 book 元素。/bookstore/book[last()]选取属于 bookstore 子元素的最后一个 book 元素。/bookstore/book[last()-1]选取属于 bookstore 子元素的倒数第二个 book 元素。/bookstore/book[position()<3]选取最前面的两个属于 bookstore 元素的子元素的 book 元素。//title[@lang]选取所有拥有名为 lang 的属性的 title 元素。//title[@lang=’eng’]选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。/bookstore/book[price>35.00]选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。/bookstore/book[price>35.00]/title选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。4.选取未知节点XPath 通配符可用来选取未知的 XML 元素。通配符描述*匹配任何元素节点。@*匹配任何属性节点。node()匹配任何类型的节点。实例路径表达式结果/bookstore/*选取 bookstore 元素的所有子元素。//*选取文档中的所有元素。//title[@*]选取所有带有属性的 title 元素。5.选取若干路径通过在路径表达式中使用“|”运算符,您可以选取若干个路径。实例:路径表达式结果//book/title \//book/price选取 book 元素的所有 title 和 price 元素。//title \// price选取文档中的所有 title 和 price 元素。/bookstore/book/title \//price选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。]]></content>
<categories>
<category>Python</category>
<category>xpath</category>
</categories>
<tags>
<tag>兴趣</tag>
<tag>教程</tag>
<tag>xpath</tag>
<tag>Python</tag>
</tags>
</entry>
<entry>
<title><![CDATA[栈和队列]]></title>
<url>%2F2019%2F06%2F26%2F%E6%A0%88%E5%92%8C%E9%98%9F%E5%88%97%2F</url>
<content type="text"><![CDATA[栈和队列栈和队列都是比较常用的数据结构。栈的应用非常的广泛,比如说,递归函数的实现就是借助于栈保存相关的数据。操作系统中每个线程也会使用栈来保存函数调用涉及到的一些参数和其他变量等。栈最大的一个特点就是先进后出(FILO—First-In/Last-Out)。队列和栈不同的是,队列是一种先进先出(FIFO—first in first out)的数据结构。1.栈头文件: #include<stack>栈是后进先出(Last In Fisrt Out)的一种特殊的线性表。栈可以存储多种类型数据,包括但不限于int char string double以及pair等等。栈的基本操作如下:12345678910111213stack<int>S; //定义栈S.push(x); //入栈——入栈是把元素压入栈底;S.pop(); //出栈——出栈是删除栈顶元素;S.top(); //取栈顶元素——取栈顶元素只返回元素,不删除;S.empty(); //判断栈是否为空——的判空一般都和 while 循环配套使用,比如下面代码输出栈内所有元素,并清空栈。若为空,则返回trueS.size(); //获取栈的大小——获取栈的大小返回栈內元素数量;注: empty的一般用法:while(!S.empty()){ cout<<S.top()<<endl; S.pop();}2.队列头文件是#include<queue>注意:一般用到优先队列的时候都会用到结构体结构体:struct 结构体名称{ }自定义命名; eg:struct node{}student;在运用结构体的时候一般在输入的时候,可以直接带着结构体的方式输入优先队列:用的时候为priority_queue详解链接:https://blog.csdn.net/c20182030/article/details/70757660friend bool operator==(const Sales_item&, const Sales_item&);的用法:1234这个函数是友元函数,返回的是bool值operator是用于运算符重载的,判断两个Sales_item类型的数据时否相等, operator是C++的关键字,它和运算符一起使用,表示一个运算符函数,理解时应将operator=整体上视为一个函数名。这是C++扩展运算符功能的方法,虽然样子古怪,但也可以理解:一方面要使运算符的使用方法与其原来一致,另一方面扩展其功能只能通过函数的方式(c++中,“功能”都是由函数实现的)。1234operator是重载的意思operator _运算符号_ (参数)所谓运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。自定义类的赋值运算符重载函数的作用与内置赋值运算符的作用类似,但是要要注意的是,它与拷贝构造函数与析构函数一样,要注意深拷贝浅拷贝的问题,在没有深拷贝浅拷贝的情况下,如果没有指定默认的赋值运算符重载函数,那么系统将会自动提供一个赋值运算符重载函数。]]></content>
<categories>
<category>图论</category>
<category>线性结构</category>
</categories>
<tags>
<tag>图论</tag>
<tag>线性结构</tag>
</tags>
</entry>
<entry>
<title><![CDATA[ACM题解]]></title>
<url>%2F2019%2F06%2F25%2F%E9%A2%98%E8%A7%A3%2F</url>
<content type="text"><![CDATA[将题解和题目集区分开主要是为了确保先思考,想方法,最后再对照题解主要还是为了养成独立思考的好习惯对应于习题集https://weakdouqing.github.io/2019/05/22/%E9%A2%98%E7%9B%AE%E9%9B%86/1.The Triangle12345678910111213141516171819202122232425262728293031323334353637题解:#include<iostream>#include<cstring>#include<algorithm>using namespace std;int a[101][101];int dp[101][101];int main(){ int n, m; int i, j; while(scanf("%d",&m)!=EOF) { memset(dp,0,sizeof(dp)); for(i=1;i<=m;i++) { for(j=1;j<=i;j++) { scanf("%d",&a[i][j]); } } for(j=1;j<=m;j++) dp[m][j] = a[m][j]; for(i=m-1;i>=1;i--) { for(j=1;j<=i;j++) { dp[i][j] = max(dp[i+1][j],dp[i+1][j+1]) + a[i][j]; } } cout<<dp[1][1]<<endl; } return 0; }2.区间完美数1234567891011121314#include<bits/stdc++.h>using namespace std;long long a,b,c,d;long long lcm(long long a,long long b){ return a*b/__gcd(a,b);}long long solve(long long x){ return x-x/c-x/d+x/lcm(c,d);}int main(){ cin>>a>>b>>c>>d; cout<<solve(b)-solve(a-1)<<endl; return 0;}3.最短路dijkstra算法写的12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#define INF 0x3fffffffusing namespace std;const int maxx=1e5; int map[110][110], dis[110], vis[110];void dijkstra(int n, int x){ int p, minn; //将所有的两点间的距离存储,并将所有点设置为未访问 for(int i = 1; i <= n; i ++) { dis[i] = map[1][i]; vis[i] = 0; } vis[x] = 1; //遍历所有点,找到最小路径 for(int i = 1; i <= n; i ++) { minn = INF; for(int j = 1; j <= n; j ++) { if(!vis[j] && dis[j] < minn) { p = j; minn = dis[j]; } } vis[p] = 1; for(int j = 1; j <= n; j ++) { if(!vis[j] && dis[p] + map[p][j] < dis[j]) { dis[j] = dis[p] + map[p][j]; } } } }int main(){ int n, m, i, j, a, b, t; //初始化距离值为无穷 while(scanf("%d %d", &n, &m)!=EOF) { if(n == 0 && m == 0) break; for(i = 1; i <= n; i ++) { for(j = 1; j <= n; j ++) { map[i][j] = INF; } } //设置两点之间的权值 for(i = 1; i <= m; i ++) { scanf("%d %d %d",&a, &b, &t); map[a][b] = map[b][a] = t; } dijkstra(n, 1); printf("%d\n",dis[n]); } return 0;}]]></content>
<categories>
<category>ACM</category>
<category>Question Solution</category>
</categories>
<tags>
<tag>ACM</tag>
</tags>
</entry>
<entry>
<title><![CDATA[next主题优化(二)]]></title>
<url>%2F2019%2F06%2F24%2Fnext%E4%B8%BB%E9%A2%98%E4%BC%98%E5%8C%96(%E4%BA%8C)%2F</url>
<content type="text"><![CDATA[Next主题优化(二)继上一次的优化没完成的部分,此次继续添加一些优化内容若是想要更多内容,可以自行百度/Google一下,继续更新内容1.字数统计和阅读时长1.安装插件npm install hexo-symbols-count-time –save2.修改站点配置文件找到合适的地方添加下面的代码1234567symbols_count_time: #文章内是否显示 symbols: true time: true # 网页底部是否显示 total_symbols: true total_time: true3.修改主题配置文件123456789101112# Post wordcount display settings# Dependencies: https://github.com/theme-next/hexo-symbols-count-timesymbols_count_time: separated_meta: true #文章中的显示是否显示文字(本文字数|阅读时长) item_text_post: true #网页底部的显示是否显示文字(站点总字数|站点阅读时长) item_text_total: false # Average Word Length (chars count in word) awl: 4 # Words Per Minute wpm: 2752.给文章添加阴影效果打开themes/next/source/css/_custom/custom.styl,添加下面的代码:12345678// 为文章添加阴影效果.post { margin-top: 60px; margin-bottom: 60px; padding: 25px; -webkit-box-shadow: 0 0 5px rgba(202, 203, 203, .5); -moz-box-shadow: 0 0 5px rgba(202, 203, 204, .5);}3.添加宠物1.安装依赖包安装依赖包,在站点根目录,打开Git Bash ,安装hexo-helper-live2d在站点配置文件或者主题配置文件添加以下内容1234567891011121314live2d: enable: true scriptFrom: local pluginRootPath: live2dw/ pluginJsPath: lib/ pluginModelPath: assets/ model: use: live2d-widget-model-wanko display: position: right width: 150 height: 300 mobile: show: true2.安装想要的宠物文件npm install {packagename}Eg:如果安装下面图示的宠物/1.png)如效果图所示的宠物名为haruto, 则为 npm install live2d-widget-model-haruto,其他宠物包点击live2d-widget-models。如果需要修改宠物的位置,可以在display下添加1234# 水平位置hOffset: 0# 垂直位置vOffset: -204.添加网站已运行时间在themes/layout/_parrials/footer.swing中添加12345678910111213141516171819202122232425262728<span id="sitetime"></span><script language=javascript> function siteTime(){ window.setTimeout("siteTime()", 1000); var seconds = 1000; var minutes = seconds * 60; var hours = minutes * 60; var days = hours * 24; var years = days * 365; var today = new Date(); var todayYear = today.getFullYear(); var todayMonth = today.getMonth()+1; var todayDate = today.getDate(); var todayHour = today.getHours(); var todayMinute = today.getMinutes(); var todaySecond = today.getSeconds(); var t1 = Date.UTC(2018,06,07,12,00,00); // 设置建立网站的时间 var t2 = Date.UTC(todayYear,todayMonth,todayDate,todayHour,todayMinute,todaySecond); var diff = t2-t1; var diffYears = Math.floor(diff/years); var diffDays = Math.floor((diff/days)-diffYears*365); var diffHours = Math.floor((diff-(diffYears*365+diffDays)*days)/hours); var diffMinutes = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours)/minutes); var diffSeconds = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours-diffMinutes*minutes)/seconds); document.getElementById("sitetime").innerHTML=" 已运行"+diffYears+" 年 "diffDays+" 天 "+diffHours+" 小时 "+diffMinutes+" 分钟 "+diffSeconds+" 秒"; } siteTime();</script>5.添加标签云在next/layout/page.swig中,找到123<div class="tag-cloud-tags"> {{ tagcloud({min_font: 12, max_font: 30, amount: 300, color: true, start_color: '#ccc', end_color: '#111'}) }} </div>如果你想卷标页先显示标签云,再显示基本的卷标页,可以在这段代码之前添加123456789101112{% if site.tags.length > 1 %}<script type="text/javascript" charset="utf-8" src="/js/tagcloud.js"></script><script type="text/javascript" charset="utf-8" src="/js/tagcanvas.js"></script><div class="widget-wrap"> <h3 class="widget-title">Tag Cloud</h3> <div id="myCanvasContainer" class="widget tagcloud"> <canvas width="250" height="250" id="resCanvas" style="width=100%"> {{ list_tags() }} </canvas> </div></div>{% endif %}如果是先显示默认的卷标页,再显示标签云,则把上面代码添加到后面。如果你只想显示标签云就行,可以把123<div class="tag-cloud-tags"> {{ tagcloud({min_font: 12, max_font: 30, amount: 300, color: true, start_color: '#ccc', end_color: '#111'}) }} </div>删去就行6.修改界面内容显示区域宽度Next主题默认的设置,两边留白的区域很大。当然我们可以修改设置在themes\next\source\css_custom的custom.styl添加下面参数12345// 屏幕宽度小于1600px$content-desktop = 700px// 屏幕宽度大于或等于 1600px$content-desktop-large = 900px只需要修改对应的参数就行,要注意的是,此方法不适用于Pisces主题]]></content>
<categories>
<category>Hexo</category>
</categories>
<tags>
<tag>兴趣</tag>
<tag>教程</tag>
<tag>Hexo</tag>
</tags>
</entry>
<entry>
<title><![CDATA[next主题优化(一)]]></title>
<url>%2F2019%2F06%2F22%2Fnext%E4%B8%BB%E9%A2%98%E4%BC%98%E5%8C%96(%E4%B8%80)%2F</url>
<content type="text"><![CDATA[Next主题优化(一)搭建完blog肯定要优化一下,不然界面你不会觉得丑吗?这篇文章将写一些能够优化界面的方法,没有的地方请自行搜索补充修改Hexo站点配置文件12345678910111213141516# Site 网站title: Dou Qing #网站标题subtitle: ~~愿你天黑有灯,下雨有伞~~ #网站副标题description: 学无止境 #网站描述author: Yan #博主的名字language: zh-Hans #网站使用的语言 PS:如果设置完后没有效果的话,去\themes\landscape\languages里面查看有的语言,一般会有zh-CN,这个就是中文timezone: #网站时区。Hexo 默认使用您电脑的时区# 侧边栏头像设置# Sidebar Avataravatar: # In theme directory (source/images): /images/avatar.gif # In site directory (source/uploads): /uploads/avatar.gif # You can also use other linking images. url: /images/图片名字 把你的头像设置在这里 #/images/avatar.gif其余的可以看着设置,不想设置的就不设置Hexo主题配置文件(next)next更多内容参考:http://theme-next.iissnan.com/theme-settings.html重点!!!!优化的重点!!想要花里胡哨的特效就认真对待这个文件打开Hexo目录/themes/next/_config.yml文件开启打赏功能123reward_comment: 坚持原创技术分享,您的支持将鼓励我继续创作!wechatpay: 你的微信收款码链接alipay: 你的支付宝收款码链接开启友情链接123456789# Blog rollslinks_icon: linklinks_title: 友情链接 //自己命名即可links_layout: block#links_layout: inlinelinks: #Title: http://example.com 在这开始写你想要的友情链接选择Scheme123456789# ---------------------------------------------------------------# Scheme Settings# ---------------------------------------------------------------# Schemesscheme: Pisces#scheme: Mist#scheme: Pisces#scheme: Gemini设置首页不显示全文打开主题配置文件_config.yml,ctrl + F搜索找到”auto_excerpt”,找到12345# Automatically Excerpt. Not recommand.# Please use <!-- more --> in the post to control excerpt accurately.auto_excerpt:enable: falselength: 150把enable改为对应的false改为true,length就是预览显示的文字长度,你可以根据你的需要进行更改,然后重新部署,再进主页,你就发现你首页的文章多了一个阅读全文的按钮。分类和标签设置首先通过hexo n “name”命令来新建一个页面,在source/_posts目录下找到刚才新建的name.md文件,用notepad++或者sublime text打开12345title: namedate: 2014-08-05 11:15:00tags:---大概这个样子,可以编辑标题、日期、标签和内容,但是没有分类的选项。我们可以手动加入categories:项,但是下次创建新的页面的时候还是没有,所以我们直接打开scaffolds/post.md文件,在tages:上面加入categories:,保存后,重新执行hexo n ‘name’命令,会发现新建的页面里有categories:项了。scaffolds目录下,是新建页面的模板,执行新建命令时,是根据这里的模板页来完成的,所以可以在这里根据你自己的需求添加一些默认值。设置分类列表123456categories:- 大类- 中类- 小类...---每一层- 内容的下面都是一种包含关系,而不是同级,这点要和标签分开在这里category_map:是设置分类的地方,每行一个分类,冒号前面是分类名称,后面是访问路径。可以提前在这里设置好一些分类,当编辑的文章填写了对应的分类名时,就会自动的按照对应的路径来访问。设置标签12345678tags:- 标签1- 标签2- 标签3- 标签4...- 标签n---背景设置静态背景修改themes\next\source\css\ _custom\custom.styl文件,这个是Next故意留给用户自己个性化定制一些样式的文件,添加以下代码:123456body { background-image: url(/images/(你想设置的)背景图片名称.png); background-attachment: fixed; background-repeat: repeat; background-size: contain;}background-image: 你想放置图片的urlbackground-attachment: 不随屏幕滚动而滚动background-repeat: 如果背景图不够屏幕大小则重复铺,改为no-repeat则表示不重复铺background-size: 等比例铺满屏幕将背景图命名为 (你想设置的)背景图片名称.png并放入主题根目录/images下或者可以直接用自动切换图片,url为:https://source.unsplash.com/random/1600x900修改不透明度这个主要是为了避免next的过于简洁的界面而造成看起来过于单一完成这一步其实背景就会自动更换了,但是会出现一个问题,因为next主题的背景是纯透明的,这样子就造成背景图片的影响看不见文字,这对于博客来说肯定不行。那么就需要调整背景的不透明度了。同样是修改themes\next\source\css\ _custom\custom.styl文件。在后面添加如下代码1234567.main-inner { margin-top: 60px; padding: 60px 60px 60px 60px; background: #fff; opacity: 0.8; min-height: 500px;}background: #fff; 颜色设置opacity: 0.8;不透明度设置:范围(0-1)PS: 如果设置完没有效果的话,打开你的blog的界面,F12,打开源代码审查页面,找到不合适的地方,根据html的语法和方式修改即可,若是没学过html+css的朋友可以借鉴一下下个网址一个简单方便学习html+css的网站: http://www.w3school.com.cn/动态可交互背景(js引入)打开博客根目录/themes/next/layout/_layout.swig文件,在之前添加代码如下:1234{% if theme.canvas_nest %}<script type="text/javascript"color="0,0,255" opacity='0.7' zIndex="-2" count="99" src="//cdn.bootcss.com/canvas-nest.js/1.0.0/canvas-nest.min.js"></script>{% endif %}属性说明:12345属性说明: - color :线条颜色, 默认: ‘0,0,0’;三个数字分别为(R,G,B) - opacity: 线条透明度(0~1), 默认: 0.5 - count: 线条的总数量, 默认: 150 - zIndex: 背景的z-index属性,css属性用于控制所在层的位置, 默认: -1打开博客根目录/themes/next/_config.yml,找到字段canvas_nest,将其置为true【如果没有找到该字段,请自行添加】运行 hexo clean && hexo g && hexo d 查看效果为文章加密方法:打开themes->next->layout->_partials->head.swig文件,在以下位置插入这样一段代码:12345678910<script> (function(){ if('{{ page.password }}'){ if (prompt('请输入文章密码') !== '{{ page.password }}'){ alert('密码错误!'); history.back(); } } })();</script>然后写文章的时候在头部加上:password: 你想要设置的密码添加RSS什么是RSS?RSS也就是订阅功能,你可以理解为类似与订阅公众号的功能,来订阅各种博客,杂志等等。为什么要用RSS?就如同订阅公众号一样,你对某个公众号感兴趣,你总不可能一直时不时搜索这个公众号来看它的文章吧。博客也是一样,如果你喜欢某个博主,或者某个平台的内容,你可以通过RSS订阅它们,然后在RSS阅读器上可以实时推送这些消息。现在网上的垃圾消息太多了,如果你每一天都在看这些消息中度过,漫无目的的浏览,只会让你的时间一点一点的流逝,太不值得了。如果你关注的博主每次都发的消息都是精华,而且不是每一天十几条几十条的轰炸你,那么这个博主就值得你的关注,你就可以通过RSS订阅他。在我的理解中,如果你不想每天都被那些没有质量的消息轰炸,只想安安静静的关注几个博主,每天看一些有质量的内容也不用太多,那么RSS订阅值得你的拥有。添加RSS功能先安装RSS插件npm i hexo-generator-feed然后再根目录下找到12345678910# Extensions## Plugins: https://hexo.io/plugins/#RSS订阅plugin:- hexo-generator-feed#Feed Atomfeed: type: atom path: atom.xml limit: 20这个时候你的RSS链接就是 域名/atom.xml了。所以,在主题配置文件中的这个social links,开启RSS的页面功能,这样你网站上就有那个像wifi一样符号的RSS logo了,注意空格。rss: /atom.xml如何关注RSS?首先,你需要一个RSS阅读器,在这里我推荐inoreader,宇宙第一RSS阅读器,而且中文支持的挺好。不过它没有PC端的程序,只有网页版,chrome上有插件。在官网上用google账号或者自己注册账号登录,就可以开始你的关注之旅了。每次需要关注某个博主时,就点开他的RSS链接,把链接复制到inoreader上,就能关注了,当然,如果是比较大众化的很厉害的博主,你直接搜名字也可以的,比如每个人都非常佩服的阮一峰大师,直接在阅读器上搜索阮一峰,应该就能出来了。我关注的比如,阮一峰的网络日志,月光博客,知乎精选等,都很不错。当然,还有我!!赶快关注我吧!你值得拥有:http://fangzh.top/atom.xml在安卓端,inoreader也有下载,不过因为国内google是登录不了的,你需要在inoreader官网上把你的密码修改了,然后就可以用账户名和密码登录了。在IOS端,没用过,好像是reader 3可以支持inoreader账户,还有个readon也不错,可以去试试。]]></content>
<categories>
<category>Hexo</category>
</categories>
<tags>
<tag>兴趣</tag>