枚举、思维
1.农夫约翰的奶酪块
农夫约翰有一块立方体形状的奶酪,它位于三维坐标空间中,从 (0,0,0) 延伸至 (N,N,N)。
农夫约翰将对他的奶酪块执行一系列 Q 次更新操作。
对于每次更新操作,农夫约翰将从整数坐标 (x,y,z) 到 (x+1,y+1,z+1) 处切割出一个 1×1×1 的奶酪块,其中 0≤x,y,z<N
输入保证在农夫约翰切割的位置上存在一个 1×1×1 的奶酪块。
由于农夫约翰正在玩牛的世界,当下方的奶酪被切割后,重力不会导致上方的奶酪掉落。
在每次更新后,输出农夫约翰可以将一个 1×1×N 的砖块插入奶酪块中的方案数,使得砖块的任何部分都不与剩余的奶酪重叠。
砖块的每个顶点在全部三个坐标轴上均必须具有整数坐标,范围为 [0,N]。
农夫约翰可以随意旋转砖块。
输入格式
输入的第一行包含 N 和 Q。
以下 Q 行包含 x,y 和 z,为要切割的位置的坐标。
输出格式
在每次更新操作后,输出一个整数,为所求的方案数。
数据范围
2≤N≤1000,
1≤Q≤2×10^5,
0≤x,y,z<N
输入样例:
2 5
0 0 0
1 1 1
0 1 0
1 0 0
1 1 0
输出样例:
0
0
1
2
5
样例解释
在前三次更新操作后,[0,1]×[0,2]×[0,1] 范围的 1×2×1 砖块与剩余的奶酪不重叠,因此它贡献了答案。

根据题意可以发现,1 x 1 x N 的奶酪块只有三种情况

第一种只用管x、z的贡献,第二种只用管x、y的贡献,第三种只用管y、z的贡献
代码:
def main():
n, q = map(int, input().split())
a = [[0] * (n + 1) for _ in range(n + 1)]
b = [[0] * (n + 1) for _ in range(n + 1)]
c = [[0] * (n + 1) for _ in range(n + 1)]
ans = 0
for i in range(q):
x, y, z = map(int, input().split())
a[x][y] += 1
b[x][z] += 1
c[y][z] += 1
if a[x][y] == n:
ans += 1
if b[x][z] == n:
ans += 1
if c[y][z] == n:
ans += 1
print(ans)
main()
2.哞叫时间
农夫约翰正在试图向埃尔茜描述他最喜欢的 USACO 竞赛,但她很难理解为什么他这么喜欢它。
他说「竞赛中我最喜欢的部分是贝茜说 『现在是哞哞时间』并在整个竞赛中一直哞哞叫」。
埃尔茜仍然不理解,所以农夫约翰将竞赛以文本文件形式下载,并试图解释他的意思。
竞赛被定义为一个长度为 N 的小写字母字符串。
一种哞叫一般地定义为子串 cicjcj,其中某字符 ci 之后紧跟着 2 个某字符 cj,且 ci≠cj。
根据农夫约翰的说法,贝茜哞叫了很多,所以如果某种哞叫在竞赛中出现了至少 FF 次,那可能就是贝茜发出的。
然而,农夫约翰的下载可能损坏,文本文件可能存在至多一个字符与原始文件不同。
将可能的误差考虑在内,输出所有可能是贝茜发出的哞叫,按字母顺序排序。
输入格式
输入的第一行包含 N 和 F,表示字符串的长度以及贝茜的哞叫的频次下限。
第二行包含一个长度为 N 的小写字母字符串,表示竞赛。
输出格式
输出可能是贝茜发出的哞叫的数量,以下是按字典序排序的哞叫列表。
每行输出一种哞叫。
数据范围
3≤N≤20000
1≤F≤N
输入样例1:
10 2
zzmoozzmoo
输出样例1:
1
moo
样例1解释
在这个样例中,任何字符变化都不会影响答案。
唯一贝茜可能发出的哞叫是 moo。
输入样例2:
17 2
momoobaaaaaqqqcqq
输出样例2:
3
aqq
baa
cqq
样例2解释
在这个样例中,位置 88(从零开始索引)的 a 可能是由 b 损坏导致的,这使得 baa 成为一种贝茜发出两次的可能的哞叫。
此外,位置 1111 的 q 可能是由 c 损坏导致的,这使得 cqq 成为一种贝茜可能的哞叫。
aqq 可以通过将 c 换成 a 来达到。
输入样例3:
3 1
ooo
输出样例3:
25
aoo
boo
coo
doo
eoo
foo
goo
hoo
ioo
joo
koo
loo
moo
noo
poo
qoo
roo
soo
too
uoo
voo
woo
xoo
yoo
zoo
这个问题不是非常直观,暴力去做的话就是O(n^2)写两个for循环,这样就超时了。按照y总的思路就是先去遍历一遍有多少直接是abb形式的,然后再去枚举每个位置变化的情况。那这样的话就需要不断的恢复现场,有点回溯的意思。建议直接去听y总讲
代码
from collections import *
def main():
n, m = map(int, input().split())
s = input()
ls = list(s)
mp = defaultdict(int)
ans = []
def update(l, r, v):
l, r = max(0, l), min(n - 1, r)
i = l
while i + 2 <= r:
if ls[i] != ls[i + 1] and ls[i + 1] == ls[i + 2]:
ss = ''.join(ls[i:i+3])
mp[ss] += v
if mp[ss] >= m and ss not in ans:
ans.append(ss)
i += 1
update(0, n - 1, 1)
for i in range(0, n):
ch = ls[i]
update(i - 2, i + 2, -1)
for j in range(ord('a'), ord('z') + 1):
if chr(j) == ch:
continue
ls[i] = chr(j)
update(i - 2, i + 2, 1)
update(i - 2, i + 2, -1)
ls[i] = ch
update(i - 2, i + 2, 1)
ans.sort()
print(len(ans))
for ss in ans:
print(ss)
main()
3.奶牛体检
农夫约翰的 N 头奶牛站成一行,奶牛 1 在队伍的最前面,奶牛 N 在队伍的最后面。
农夫约翰的奶牛也有许多不同的品种。
他用从 1 到 N 的整数来表示每一品种。
队伍从前到后第 i 头奶牛的品种是 ai。
农夫约翰正在带他的奶牛们去当地的奶牛医院进行体检。
然而,奶牛兽医非常挑剔,仅愿意当队伍中第 i 头奶牛为品种 bi 时对其进行体检。
农夫约翰很懒惰,不想完全重新排列他的奶牛。
他将执行以下操作恰好一次。
- 选择两个整数 l 和 r,使得 1≤l≤r≤N。反转队伍中第 l 头奶牛到第 r 头奶牛之间的奶牛的顺序。
农夫约翰想要衡量这种方法有多少效果。
对于每一个 c=0…N,请帮助农夫约翰求出使得恰好 c 头奶牛被检查的不同操作 (l,r) 的数量。
两种操作 (l1,r1) 和 (l2,r2) 不同,如果 l1≠l2 或者 r1≠r2。
输入格式
输入的第一行包含 N。
第二行包含 a1,a2,…,aN。
第三行包含 b1,b2,…,bN。
输出格式
输出 N+1 行,第 ii 行包含使得 i−1 头奶牛被检查的不同操作 (l,r) 的数量。
数据范围
1≤N≤7500
1≤ai,bi≤N
输入样例1:
3
1 3 2
3 2 1
输出样例1:
3
3
0
0
样例1解释
如果农夫约翰选择 (l=1,r=1),(l=2,r=2) 或 (l=3,r=3),则没有奶牛将会被检查。
注意这些操作并没有改变奶牛的位置。
以下操作会导致一头奶牛被检查。
- (l=1,r=2):农夫约翰反转第一头和第二头奶牛的顺序,因此新队伍中每头奶牛的品种将为 [3,1,2]。第一头奶牛将会被检查。
- (l=2,r=3):农夫约翰反转第二头和第三头奶牛的顺序,因此新队伍中每头奶牛的品种将为 [1,2,3]。第二头奶牛将会被检查。
- (l=1,r=3):农夫约翰反转第一头,第二头和第三头奶牛的顺序,因此新队伍中每头奶牛的品种将为 [2,3,1]。第三头奶牛将会被检查。
输入样例2:
3
1 2 3
1 2 3
输出样例2:
0
3
0
3
样例2解释
三种导致 3 头奶牛被检查的可能操作为 (l=1,r=1),(l=2,r=2) 和(l=3,r=3)。
输入样例3:
7
1 3 2 2 1 3 2
3 2 2 1 2 3 1
输出样例3:
0
6
14
6
2
0
0
0
样例3解释
两种导致 4 头奶牛被检查的可能操作为 (l=4,r=5) 和 (l=5,r=7)。
这个问题直接暴力做的代码是这样的:
from collections import *
from math import *
def main():
n = int(input())
a = [0] + list(map(int, input().split()))
b = [0] + list(map(int, input().split()))
cnt = 0
for i in range(1, n + 1):
if a[i] == b[i]:
cnt += 1
ans = [0] * (n + 1)
ans[cnt] += n
for i in range(1, n + 1):
for j in range(i + 1, n + 1):
t, m = cnt, i + j
# print(f"{i} {j} : {m}")
for k in range(i, j + 1):
if a[k] == b[k]:
t -= 1
if a[m - k] == b[k]:
t += 1
ans[t] += 1
# print(f"{i} {j} : {t}")
for x in ans:
print(x)
main()
时间复杂度是O(n ^ 3)会超时,需要优化到O (n ^ 2),中间我想过用前缀和去优化,发现预处理前缀和的时间复杂度也是O (n ^ 3)的,那么这个问题就只能用小技巧或者区间 dp 了。
一个枚举的小技巧:可以从中间向两边枚举,发现每次只交换了最左边和最右边,因为中间的都被抵消了(偶消奇不消),这样的话就是 O(n ^ 2)了
代码
from collections import *
from math import *
def main():
n = int(input())
a = [0] + list(map(int, input().split()))
b = [0] + list(map(int, input().split()))
cnt = 0
for i in range(1, n + 1):
if a[i] == b[i]:
cnt += 1
ans = [0] * (n + 1)
for i in range(1, n + 1):
for j in range(0, 2):
tot = cnt
l, r = i, i + j
while l >= 1 and r <= n:
if a[l] == b[l]:
tot -= 1
if a[r] == b[r]:
tot -= 1
if a[l] == b[r]:
tot += 1
if a[r] == b[l]:
tot += 1
ans[tot] += 1
l, r = l - 1, r + 1
for x in ans:
print(x)
main()
4.眸叫时间II
农夫约翰正在试图向埃尔茜描述他最喜欢的 USACO 竞赛,但她很难理解为什么他这么喜欢它。
他说「竞赛中我最喜欢的部分是贝茜说『现在是哞哞时间』并在整个竞赛中一直哞哞叫」。
埃尔茜仍然不理解,所以农夫约翰将竞赛以文本文件形式下载,并试图解释他的意思。
竞赛被定义为一个包含 N 个整数的数组 a1,a2,…,aN。
农夫约翰定义哞叫为一个包含三个整数的数组,其中第二个整数等于第三个整数,但不等于第一个整数。
一种哞叫被称为在竞赛中发生,如果可以从数组中移除整数,直到只剩下这一哞叫。
由于贝茜据称「在整个竞赛中一直哞哞叫」,请帮助埃尔茜计算竞赛中发生的不同哞叫的数量!
两种哞叫是不同的,如果它们并非由相同的整数以相同的顺序组成。
输入格式
输入的第一行包含 N。
第二行包含 N 个空格分隔的整数a1,a2,…,aN。
输出格式
输出竞赛中发生的不同哞叫的数量。
注意这个问题涉及到的整数可能需要使用 64 位整数型(例如,Java 中的 “long”,C/C++ 中的 “long long”)。
数据范围
1≤N≤10^6,
1≤ai≤N
输入样例:
6
1 2 3 4 4 4
输出样例:
3
样例解释
竞赛包含三种不同的哞叫:1 4 4,2 4 4 和 3 4 4。
这个问题有点像两数之和的那个思想,动态的去更新。(定义 A 是眸叫的第一个元素,BB 是眸叫的第二、三元素)先统计一遍能作为 A 的放进哈希表 ist ,在从后往前,因为必须是 ABB 形式,动态的统计 BB 形式的放进哈希表 sec
代码
from collections import *
def main():
n = int(input())
a = list(map(int, input().split()))
ist = defaultdict(int) #可作为眸叫第一个数的元素个数
sec = defaultdict(int) #可作为眸叫第二和第三个数的元素个数
cnt = 0
for i, x in enumerate(a):
ist[x] += 1
if ist[x] == 1:
cnt += 1
a.reverse()
ans = 0
for i, x in enumerate(a):
sec[x] += 1
ist[x] -= 1
if ist[x] == 0:
cnt -= 1
if sec[x] == 2:
ans += cnt
if ist[x] > 0:
ans -= 1
print(ans)
main()
5. 拐杖糖盛宴
农夫约翰的奶牛们非常爱吃甜食,尤其爱吃拐杖糖。
约翰一共有 N 头奶牛,编号 1∼N,其中第 ii 头奶牛的初始高度为 ai。
约翰给奶牛们准备了 M 根拐杖糖,编号 1∼M,其中第 i 根的高度为 bi。
约翰会按照糖果的编号顺序,每次拿出一根糖果喂给奶牛们,直到所有糖果都被喂完为止。
每当拿出一根糖果后,约翰会将其上端固定悬挂,下端自由下垂至刚好接触地面。
然后,奶牛们按照编号顺序,依次走到糖果面前,将糖果自下而上的啃食至自己的高度(因为更高的地方吃不到了)。
由于糖果上端是固定的,所以即使奶牛吃掉糖果的下端部分,糖果也会悬挂在最初设置的位置,不会下降至地面。
当轮到一个奶牛时,如果糖果剩余部分的底部高度已经超过了该奶牛的高度,那么它将什么都吃不到。
在所有奶牛都轮过一次后,不论这根糖果是否被吃完,该糖果都会被约翰扔掉,并换上下一根糖果,继续下一轮次的吃糖(仍然从编号为 1 的奶牛开始)。
另外,每轮过后,糖果都有可能令奶牛们的身高有所增长,具体为一头奶牛在本轮次吃掉了多少长度的糖果,其身高就会增高多少长度。
请你计算,当所有糖果都喂食完毕后,每头奶牛的最终高度。
输入格式
第一行包含两个整数 N,M。
第二行包含 N 个整数 a1,a2,…,aN。
第三行包含 M 个整数 b1,b2,…,bM。
输出格式
共 N 行,其中第 i 行输出第 ii 头奶牛的最终高度。
数据范围
1≤N,M≤2×105
1≤ai,bi≤109
输入样例:
3 2
3 2 5
6 1
输出样例:
7
2
7
样例解释
第 1 根糖果的高度为 6:
- 第 1 头牛吃掉高度不超过 3 的部分,糖果剩余部分高度 [3,6]。
- 第 2 头牛不够高,吃不到任何糖果。
- 第 3 头牛吃掉高度不超过 5 的部分,糖果剩余部分高度 [5,6]。
第 1 根糖果喂完,奶牛们的高度变为 [3+3,2+0,5+2]=[6,2,7]。
第 2 根糖果的高度为 1,会被第 11 头奶牛全部吃掉。
所以,最终奶牛们的高度变为 [7,2,7]。
看数据范围确实会感觉直接暴力会有 O(n^2)的时间复杂度会过不了,这种时候可以先写出来,看看数据水不水(这道题是水的),当一颗糖被完全吃完时,就可以跳过后面所有的,那么如果数据水的的话就能过,这道题就是如此。因此我认为这道题如果时 ACM 赛制算最简单的题,因为能直接知道暴力能不能过,但如果是 oi 赛制可能会迷惑那些考虑周到的选手他们就会去想一些优化算法把时间复杂度优化到 O(nlogn),但是蓝桥杯么,如果没有想到完美的算法直接暴力是最好的
代码
from collections import *
def main():
n, m = map(int, input().split())
a = list(map(int, input().split()))
b = list(map(int, input().split()))
mp = defaultdict()
for i, x in enumerate(b):
mp[i] = [1, x]
for i in range(m):
l, r = mp[i]
for j, x in enumerate(a):
if l > r:
break
if x >= l:
t = min(x - l + 1, r - l + 1)
a[j] += t
l += t
for x in a:
print(x)
main()
贪心
1.密接牛追踪2
农夫约翰有 N 头奶牛排成一排,从左到右依次编号为 1∼N。
不幸的是,有一种传染病正在蔓延。
最开始时,只有一部分奶牛受到感染。
每经过一个晚上,受感染的牛就会将病毒传染给它左右两侧的牛(如果有的话)。
一旦奶牛被感染,它就会一直被感染,无法自愈。
给定一个经过若干个夜晚后的奶牛的整体状态,其中哪些奶牛已经被感染,哪些奶牛尚未被感染统统已知。
请你计算,最开始时就受到感染的奶牛的最小可能数量。
输入格式
第一行包含整数 N。
第二行包含一个长度为 N 的 01 序列,用来表示给定的奶牛的整体状态,其中第 i 个字符如果是 1 则表示第 i 头奶牛已经被感染,如果是 0 则表示第 i 头奶牛尚未被感染。
输出格式
一个整数,表示最开始时就受到感染的奶牛的最小可能数量。
数据范围
1≤N≤3×10^5
输入样例1:
5
11111
输出样例1:
1
样例1解释
初始时,任意一头奶牛被感染,一定天数后都可以使得所有奶牛被感染。
输入样例2:
6
011101
输出样例2:
4
样例2解释
唯一一种可能是给定状态是没有经过任何夜晚时所有奶牛的状态,所以输入中被感染的 4 头奶牛都在最开始时就受到感染。
这个问题需要通过数学推导得出贪心结论,首先分析一下 01 字符串,发现可以分区域分析这些连续1,记某个区域连续 1 的个数是 cnt ,r = (cnt - 1) // 2, 那么最开始的 cnt 个数就是 ceil(cnt / (2r + 1)),所以只需要算出最大的 r ,然后遍历一遍区域即可
代码
from collections import *
from functools import *
from math import *
def main():
n = int(input())
a = list(map(int, input()))
c = []
i, d = 0, inf
while i < n:
if a[i] == 0:
i += 1
continue
cnt = 0
while i < n and a[i] == 1:
cnt += 1
i += 1
ist, ed = i - cnt + 1, i
r = -1
if ist == 1 or ed == n:
r = cnt - 1
else:
r = (cnt - 1) // 2
d = min(d, r)
c.append(cnt)
ans = 0
# print(d)
# print(c)
for x in c:
ans += ceil(x / (2 * d + 1))
# print()
print(ans)
main()
2.农夫约翰最喜欢的操作
又是农夫约翰的农场上寒冷而无聊的一天。
为了打发时间,农夫约翰发明了一种关于在整数数组上进行操作的有趣的休闲活动。
农夫约翰有一个包含 N 个非负整数的数组 a 和一个整数 M。
然后,农夫约翰会请贝茜给出一个整数 x。
在一次操作中,农夫约翰可以选择一个索引 i,并对 ai 加 1 或减 1。
农夫约翰的无聊值是他必须执行的最小操作次数,以使得对于所有的 1≤i≤N,ai−x 均可被 MM 整除。
对于所有可能的 x,输出农夫约翰的最小无聊值。
输入格式
输入的第一行包含 T,为需要求解的独立的测试用例数量。
每一个测试用例的第一行包含 N 和 M。
第二行包含 a1,a2,…,aN。
输出格式
对于每一个测试用例输出一行,包含对于所有可能的 x,农夫约翰的最小无聊值。
数据范围
1≤T≤10,
1≤N≤2×10^5,
1≤M≤10^9,
0≤ai≤10^9,
输入保证所有测试用例的 N 之和不超过 5×10^5。
输入样例:
2
5 9
15 12 18 3 8
3 69
1 988244353 998244853
输出样例:
10
21
样例解释
在第一个测试用例中,x 的一个最优选择是 3。
农夫约翰可以执行 10 次操作使得 a=[12,12,21,3,12]。
首先题目要找 (a[i] - x) % m == 0 ,求其他的点到 i 这个点的最短距离。将问题转化一下,a[i] = x % m,首先是要找一个 x ,不妨直接将 a 数组取模,直接在 i ∈ [1, n] 当中找
可以想象成一个环形数组,然后经过 x 做一条割线

那么如果选定 x 了,下标 [x, n] 的到 x 的最短距离就是 i - x, 下标 [2, x] 的到 x 的最短距离就是 i - x
1 从左边和右边是一样的那么就可以从 1 断开

这样的话会发现 x 只要是 a[i] (i∈[1, n])即可,那么就很清晰了,找一个数使得其他数到这个数的距离最小,那不就是中位数吗,只不过变成了环形数组,需要枚举一遍中位数
只需要去枚举 l 即可 (l∈[l, n]),根据 l 得到 r 在得到 中位数
至于 a 数组后面为什么这样拓展,看看 d 老师的回答吧

代码
def main():
n, m = map(int, input().split())
a = [0] + list(map(int, input().split()))
s = [0] * (2 * n + 1)
for i in range(1, n + 1):
a[i] %= m
a[1:] = sorted(a[1:n+1])
for i in range(1, n + 1):
a.append(a[i] + m)
for i in range(1, 2 * n + 1):
s[i] = s[i - 1] + a[i]
ans = 10**20
for l in range(1, n + 1):
r = l + n - 1
p = (l + r) >> 1
left = a[p] * (p - l + 1) - (s[p] - s[l - 1])
right = (s[r] - s[p]) - a[p] * (r - p)
ans = min(ans, left + right)
if ans == 0:
break
print(ans)
t = int(input())
for _ in range(t):
main()
前缀和
1.蛋糕游戏
贝茜和埃尔茜发现了一行 N 个蛋糕(N 为偶数),大小依次为 a1,a2,…,aN。
两头奶牛都想吃到尽可能多的蛋糕。
但是,作为非常文明的奶牛,她们决定玩一个游戏来分割蛋糕!
游戏在两头奶牛之间轮流进行回合。
每个回合进行以下两者之一:
- 贝茜选择两个相邻的蛋糕并将它们堆叠起来,制造大小为两者大小之和的一个新蛋糕。
- 埃尔茜选择最左边或最右边的蛋糕藏起来。
当只剩下一个蛋糕时,贝茜吃掉它,而埃尔茜吃掉她藏起来的所有蛋糕。
如果两头奶牛都采取最优策略以最大化她们吃到的蛋糕量,并且贝茜先进行回合,那么每头奶牛将会吃到多少蛋糕?
输入格式
每个测试点包含 T 个独立的测试用例。
每个测试用例的格式如下。
第一行包含 N。
下一行包含 N 个空格分隔的整数 a1,a2,…,aN。
输出格式
对于每个测试用例,输出一行,包含 bb 和 ee,表示贝茜和埃尔茜在两头奶牛都采取最优策略的情况下分别吃到的蛋糕量。
数据范围
1≤T≤10,
2≤N≤5×10^5,
1≤ai≤10^9,
输入保证一个测试点中的所有 N 之和不超过 10^6。
输入样例:
2
4
40 30 20 10
4
10 20 30 40
输出样例:
60 40
60 40
样例解释
对于第一个测试用例,在最优策略下,
- 贝茜将堆叠中间两个蛋糕。现在蛋糕的大小为 [40,50,10]。
- 埃尔茜将吃掉最左边的蛋糕。现在剩余的蛋糕的大小为 [50,10]。
- 贝茜堆叠剩余的两个蛋糕。
贝茜将吃到 30+20+10=60 的蛋糕,而埃尔茜将吃到 40 的蛋糕。
第二个测试用例是第一个测试用例反转的情况,因此答案相同。
这个问题做一些数学推理,首先 n 是偶数,并且每一轮游戏之后相当于减少了两块蛋糕(A:贝茜,B:埃尔茜),A合并两块变成一块,B吃一块(注意只能吃第一个或最后一个)。发现性质1.游戏最多进行 n / 2 轮。(这个性质没有什么实际作用)。我们通过样例模拟发现如果 A 用最优策略,一定不会让 B 吃到他合并过的蛋糕,发现 A 一定会比 B 多吃两块蛋糕,性质2:在双方的最优策略下 A 最终会吃 n / 2 + 1 块,B 会吃 n / 2 - 1 块。记 sum 为蛋糕总和
我们根据性质2先分析 A 的最优解:B 已知每次吃只能吃第一个或最后一个,那么在这种情况下,A至少可以吃中间的长度为 n / 2 + 1块和最小的蛋糕(因为我们要避免 B 吃到 A 合并过的蛋糕,那么 A 每次选择就尽量避开 B 即可)。得到结论:sumA >= Smin, sum - sumB >= Smin -> sumB <= sum - Smin
再来分析 B 的最优解:B 肯定是想吃到 A 合并过的蛋糕,但是当 A 先手的情况下,A 采用最优策略一定不会让 B 迟到他合并过的蛋糕,这样的话 B 的最优策略就是尽量让 A 合并的蛋糕量小。得到结论:sumB >= sum - Smin
结合一下 sumB 直接出来了就是 sum - Smin, sumA 也出来了 sum - sumB
代码
from collections import *
from math import *
def main():
n = int(input())
s = [0] * (n + 1)
a = [0] + list(map(int, input().split()))
# print(a)
for i in range(1, n + 1):
s[i] = s[i - 1] + a[i]
S, T = sum(a), inf
mid = n // 2 + 1
for i in range(mid, n + 1):
T = min(T, s[i] - s[i - mid])
print(f"{T} {S - T}")
t = int(input())
for _ in range(t):
main()
数学
1.农夫约翰真的种地
农夫约翰在他的农场种植了 N 个芦笋,编号 1∼N。
其中,第 i 个芦笋的初始高度为 hi,每经过一天高度会增长 ai。
给定一个 0∼N−1 的排列 t1,t2,…,tN。
请问至少多少天后能够满足,对于每个 1≤i≤N,恰好有 titi 个芦笋比第 ii 个芦笋的高度更高。
输入格式
第一行包含整数 T,表示共有 T 个测试数据。
每组数据第一行包含整数 N。
第二行包含 N 个整数 h1,h2,…,hN。
第三行包含 N 个整数 a1,a2,…,aN。
第四行包含 N 个整数 t1,t2,…,tN。
输出格式
每组数据输出一行结果,一个整数表示答案,如果无解则输出 -1。
数据范围
1≤T≤10
1≤N≤2×10^5
1≤hi,ai≤10^9
0≤ti≤N−1
保证 t1∼tN 是一个 0∼N−1 的排列,
一个测试点内所有的 N 相加之和不超过 2×10^5。
输入样例1:
6
1
10
1
0
2
7 3
8 10
1 0
2
3 6
10 8
0 1
2
7 3
8 9
1 0
2
7 7
8 8
0 1
2
7 3
8 8
1 0
输出样例1:
0
3
2
5
-1
-1
样例1解释
第 1 组数据,由于只有一个芦笋,所以不需要经过任何天数,第 0 天即可满足条件。
第 2 组数据,我们需要使得第 1 个芦笋比第 2 个芦笋更矮:
天数 芦笋1 芦笋2
0 7 3
1 15 13
2 23 23
3 31 33
经过 3 天后,即可满足条件。
第 3,4 组数据与第 2 组数据类似。
第 5 组数据,两个芦笋的初始高度和生长速度都相同,所以永远保持相同高度,一定无法满足条件。
第 6 组数据,两个芦笋的初始高度不满足条件,生长速度都相同,所以永远不可能满足条件。
输入样例2:
2
5
7 4 1 10 12
3 4 5 2 1
2 1 0 3 4
5
4 10 12 7 1
3 1 1 4 5
2 4 3 1 0
输出样例2:
4
7
样例2解释
第 1 组数据,4 天后各个芦笋的最终高度为 19,20,21,18,16。
第 2 组数据,7 天后各个芦笋的最终高度为 25,17,19,35,36。
这个问题是一道数学题,需要一些数学推理。首先我们将问题给定的条件转化一下,给定 ti 表示:恰好有 ti 个芦笋比第 i 个芦笋的高度更高。那么就可以推理出最终的排名(按高度排序)
根据最终的排名会得到 h1 - a1 * day > h2 + a2 * day, h2 - a2 * day > h3 + a3 * day .......
我们要求最小的 day ,那么就是求一个范围使得所有区间有交集,最后输出左边界,如果有一个区间不满足(也就是没有交集)那么就无解
代码
from math import *
class D:
def __init__(self, h, x, t, r):
self.h = h
self.x = x
self.t = t
self.r = r
def main():
n = int(input())
h = list(map(int, input().split()))
x = list(map(int, input().split()))
t = list(map(int, input().split()))
a = []
for i in range(n):
a.append(D(h[i], x[i], t[i], t[i] + 1))
a.sort(key = lambda d : d.r)
l, r = 0, inf
for i in range(0, n - 1):
# print(a[i].r, end = ' ')
A, B = a[i].h - a[i + 1].h, a[i + 1].x - a[i].x
# print(f"{A} {B}")
if B > 0:
r = min(r, int(ceil(A / B)) - 1)
elif B < 0:
l = max(l, int(floor(A / B)) + 1)
elif A <= 0:
r = -1
break
if l > r:
l = -1
print(l)
T = int(input())
for _ in range(T):
main()
加油
326

被折叠的 条评论
为什么被折叠?



