2022CCPC威海:A、C、E、G、I、J
目前这5题让我觉着,威海这场思路倒不是多难,但是代码我觉着很难写,比如c和j。
问题解析
题目很怪,看了好多次。
题目说有个比赛,先给你n行,每行5个人,这五个人的顺序是他们比赛的位置(1~5),这n行是之前比赛的冠军,再给你m个人,每个人有对应的位置,问你最多能组成多少队伍参加比赛,每个队伍里都至少要有一个冠军,每个人的位置不能变。
一开始想的能组多少不同的队伍,这样就是每个位置的不同人数和冠军的数量来算,但是显然样例1就不对劲。后来发现是能组成的队伍数,不是不同的队伍数。
- 那就计算每个位置的人数,如果不考虑冠军的因素,能组成的最多队伍数就等于这五个位置里人数最少的数量(比如1到4位置都有10人,但位置5只有1人,那就只能组成1个队伍,木桶原理)。
- 如果要考虑冠军因素,那贪心的来想,就是每个队伍一个冠军,那能组成的队伍数就是冠军的数量。
答案就是两者中的最小值。
AC代码
#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
- 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
问题解析
题目说给你n个点,问你能不能找到五个点ABCDE,让线段AB、AC、AD、AE之间不发生交叉。
很显然,要是给的点不够5个,就直接输出NO。
我们也可以想出,只要BCDE四个点不是都和A共线的,就能有结果,哪怕BCDE四个点都是共线。

也就说重点不在BCDE上,而是在点A上。
对于给的n个点,我们之间把前四个点记录下来,然后从剩下的点里面找第五个点。每次我们假设这五个点是答案送去判断,如果能组成答案就输出,不能我们就找下一个点当作第五个点,以此类推,要是找完了还没能出结果,说明没有答案,输出NO。
至于判断五个点是不是答案,我们枚举每个点当作是A,剩下的当作BCDE,然后看他们和A的共线情况。
这里我是判断他们和A的斜率:**(y2-y1)/(x2-x1)**是否相同。如果都不相同,说明当前枚举的点A就可以是一个合格的答案。
如果有两个斜率相同,说明这两个点和A共线,那么,当且仅当A是在这俩点中间时,才是正确的,比如:

而如果A不在两点之间,显然答案不对的,比如:

至于判断A是否在BC之间,只要看AB+AC是否等于BC即可。
AC代码
#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
- 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
问题解析
题目是说给你一个长度为n的数组和一个数k,要你找到第一个小于k的数的位置,如果数组没有,那你可以扩展数组:ai=a(i-1)*2-a(i-2);
直到找到小于k的数位置,如果永远也找不到,输出永远也找不到。
没啥想法,就想着先把数组扩展到1e6个数,如果找到了就输出位置,找不到就输出永远也找不到。
然后就过了,笑死。
AC代码
#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
- 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
问题解析
题目说给你一个数x和m次询问,每次询问给一个区间l~r,问你l到r里有几个数k能够满足gcd((k*x ^ x),x)=1.
找规律题,对于数字x,它的答案其实是有一个长度为2^(log2(x))的循环节(循环节长度就是第一个大于x的2的次幂)。
因为x最大也就1e6,我们可以先把循环节的答案给算出来,一个循环节的k的个数我们记作cnt,然后每次询问,根据区间的长度能分成三部分:
- 最左边的部分,这一部分不是一个完整的循环节。
- 中间的部分,包含了复数个循环节。
- 最右边的部分,这一部分也不是一个完整的循环节。
中间的部分,我们可以通过计算出循环节的个数*cnt得到结果。
至于左边和右边的部分,一开始我用for循环一个个找,然后t了,想了想最坏的情况每次询问我们都要搜1e6左右的长度,复杂度就变成n^2了,慢死。
我们在计算循环节的时候,顺便准备一个前缀和数组sum,sum[i]表示0到i有多少个结果。这样左边和右边的部分我们就能通过前缀和数组算出结果了。
AC代码
#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
- 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
问题解析
题目是说要下龙蛋,每下一个龙蛋需要n种元素各a[i]个,现在有k种工具龙去收集元素,第i种工具龙能收集单类元素2^(i-1) 个,问你最多能下几个蛋。
能生x个蛋就肯定能生x-1个蛋,有可能能生x+1个蛋,这就有单调性了,于是二分答案。
把生mid个蛋所需要的各类元素数量都存入单调队列里,优先收集所需量多的元素,我们尽量选高级的工具龙去收集,每次要么一次性收集完当前元素,要么一次性用完当前工具龙,防止浪费,浪费的龙越少,能收集的元素就越多,能生的蛋可能就更多。
(二分上限的边界不好找,于是直接算了一下极限情况下这些工具龙能让我们生的最多蛋数来做上限)
AC代码
#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
- 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
问题解析
题目是说给你n个数,以及m个限制,每个限制有两个数x和y,表示数x最多只能同时出现y个,每次两个玩家会选一个数-1,最先做不出操作的就输了。
一开始看见博弈吓得很,但是看了题目发现他们每轮的操作并没有多花哨,根据奇偶性就能求出结果。
按照限制中,y=0的地方分割数,如果x最多出现次数为0,说明比他大的数都只能停在x+1上了,不能更小。
然后剩下的数则能删多小删多小。
但是可能会出现x出现次数为0,x+1出现次数为1的限制。
(个人感觉思路不难,但是代码有点麻烦,文字不好说,看代码注释罢)
AC代码
#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
- 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