代码(java)已经分享在Github上:https://github.com/CCSClassBattlecruiser/660div2
个人水平有限,如有错误还请在评论区指出 谢谢!
Problem A. Captain Flint and Crew Recruitment
https://codeforces.com/contest/1388/problem/A
题目大意: 如果一个整数x可以被表示成两个质数p和q(p≠q)的积,那我们可以把他叫做为近质数.
输入一个整数n,请将它表示成四个不同的正整数的和,要求其中三个是近质数
我们先列出最小的近质数并寻早规律.
可以看到,最小的三个近质数分别为2*3,2*5,2*7 (6,10,14)
那也就是说,小于(6+10+14+1 = 31) 的n无法被如此表示.
接下来我们考虑重复的情况. 当n大于(6+10+14+14 = 44)的时候,无需考虑重复问题.
那就只需要看看三个特例(6,10,14重复)能不能被其他的方案排列.
3*5 15也是近质数,因此我们很容易得到
6 10 14 6 的替代: 6 10 15 5
6 10 14 10 的替代: 6 10 15 9
6 10 14 14 的替代: 6 10 15 13
对这三个特例做一个特判即可 时间复杂度为O(1)
Problem B. Captain Flint and a Long Voyage
https://codeforces.com/contest/1388/problem/B
题目大意:给定一个n, 写出一个最小的n位十进制数字x, 使得x的每一位的二进制表示组成的二进制数字k在被抹去最后n位之后最大. 例: n=3, x=729, 729 组成的 k = 111101001(7=111, 2=10,9=1001), 抹去最后n位后, k=111101
在继续之前,我们先列出0-9的二进制表示, 相信很多MC玩家对BCD非常熟悉
0 = '0'
1 = '1'
2 ='10'
3 = '11'
4 = '100'
5 = '101'
6 = '110'
7 = '111'
8 = '1000'
9 = '1001'
可以看到,如果我们想要使得k最大,那我们就需要尽可能多的位数, 只有8和9的二进制表示是4位二进制数. 在没有抹去最后n位数字的条件下, 完全由9组成的x所组成的k一定是最大的k , 那么另外一个条件是找到最小的 x. 我们可以看到, 如果换成8和9以外的任意数字 那么k的长度一定会下降, 抹去n位以后的长度也一定会下降. 因此k的大小也会下降.
那现在我们只需要考虑一个由9和8组成的x, 观察二进制表示, 我们可以发现, 当被抹去一位的时候, 8和9的二进制表示是相同的. 也就是说, 如果抹去n位, 那么我们就可以把x的最后的n/4+1位换成8, 得到的k值是不变的. 我们不能把x的前面几位替换成8,因为这样会降低k的大小
按此逻辑将x输出即可, 时间复杂度为O(1)
Problem C. Uncle Bogdan and Country Happiness
https://codeforces.com/contest/1388/problem/C
这题题目废话太多, 我来稍微总结一下:
叫你不开采奢侈品(文明玩家乱入
有n个城市组成的组成了一颗树, 这棵树有n-1条边,
城市1为这棵树的根.
每个城市有自己的人口, 同时有一个快乐监视器.
所有城市的居民都在城市1工作, 他们在晚上会以最短路径回到自己的城市
居民在回家的时候可能有一个好心情,也可能有坏心情. 居民的心情可能会在半路变坏, 但是不可能在半路变好.
快乐监视器会输出一个快乐值,这个快乐值等于所有经过该城市的快乐的居民的数量-经过该城市的不快乐的居民的数量
现在你需要判断出,这个快乐监视器有没有正常工作.
首先我们要根据题意判断出快乐监视器正常工作的条件:
题目里的两个规则可以衍生出三条正确工作的条件.
根据快乐值等于所有经过该城市的快乐的居民的数量-经过该城市的不快乐的居民的数量:
我们可以判断出以下两个规则:
1.经过城市的人口+城市快乐值 是二的倍数,也就是 (经过城市的人口-城市快乐值)%2==0
假设经过该城人口为x, 快乐值为h 那么经过该城市里有好心情的人数等于 (x+h)/2,由于不可能有半个人,所以经过该城市人口+城市快乐值一定是二的倍数
2. 城市的快乐值∈[经过城市的人口,-经过城市的人口]
这条规则很简单, 城市的最大的快乐值就是当经过城市的所有人都是快乐的情况下, 也就是快乐值等于经过的人口数量. 城市的最小快乐值就是当经过城市的所有人都是不快乐的情况下, 也就是快乐值等于-人口数量.
根据居民的心情可能会在半路变坏, 但是不可能在半路变好.
我们可以推断出以下规则:
3. 一个城市所有子节点的快乐值的和减去该城市人口小于该城市的快乐值.
这条规则也很简单, 该城市的快乐值为所有经过该城市的快乐的居民的数量-经过该城市的不快乐的居民的数量, 子节点的快乐值的和为 所有离开该城市的快乐的居民的数量-离开该城市的不快乐的居民的数量, 所有离开该城市的居民数量等于所有经过该城市的居民数量减去该城市的居民数量. 因为经过该城市的不快乐的居民数量 ≤ 开该城市的不快乐的居民的数量 所以一个城市所有子节点的快乐值的和减去该城市人口小于该城市的快乐值
理解规则以后就很好做了, 用DFS挨个城市判断即可
时间复杂度为O(n)
Problem D. Captain Flint and Treasure
https://codeforces.com/contest/1388/problem/D
题目大意:
有长度为n的两个数组a和b, 你需要执行如下操作n次
选择一个i, 1 ≤ i ≤ n 每一个i只能选择一次
将a[i]加入ans, 如果bi≠ -1, 把a[bi]加上a[i]
ans += a[i] , a[bi] += a[i]
求ans的最大值, 并输出步骤.
为了区分原始的a[i]和操作之后的a[i], 我使用aUpdated[i] 来表示经过操作的a[i]
我们可以以bi = -1 的i 为根构建一棵树, 子节点为 b[i] = i 的 i,
对其进行DFS, 当aUpdated[i] > 0的时候 执行一次操作, 并将操作步骤按照子节点->父节点
保存到一个储存步骤的容器P里
更新父节点的值. 我们可以看到, 当子节点的值aUpdated[i] > 0的时候, 子节点先于父节点操作是可以提高ans的值的 同时当我们更新处理完所有的子节点之后, 父节点的值aUpdated[i] 会更新到父节点可能的最大值
对于叶子来说, aUpdated[i] = a[i]
而当子节点的值aUpdated[i]<0的时候, 父节点需要优先于子节点操作. 否则会降低ans的值当我们处理完所有aUpdated[i] > 0的步骤的时候 再进行一次DFS把子节点小于0的情况按照父节点->子节点的顺序保存到另外一个储存步骤的容器N中, 那么最后 P+N 就是这棵树的最优步骤. 我们把所有执行过操作的i 用一个used[] 数组标记出来.
每一颗树之间是独立的, 因此先构建哪一颗树不会影响最后的答案.
最后把所有没有执行过操作的i以任意顺序加入操作步骤即可.
而ans 则是执行完所有DFS操作的aUpdate[i]的和
Problem E. Uncle Bogdan and Projections
https://codeforces.com/contest/1388/problem/E
我不会做 别骂了>_<