d这套题,第一题数学找规律、第二题也是掺杂一些数学的模拟、第三题是动态规划。整体题目代码量不大,但是比较灵活,考验思维的敏捷度。
一、下雪
题目描述
村子里有一些桩子,从左到右高度依次为1,1+2,1+2+3,...,每两颗桩子之间的间隔为1。
现在下了一场大雪,但是不知道雪下了多厚,现在给你两个数字,这是雪后某相邻两个桩子在雪面的高度,请你通过这两个数字计算雪的厚度。
输入描述
第一行输入两个整数a,ba,b
1≤a<b≤5∗1051≤a<b≤5∗105
输出描述
一个整数代表答案,保证答案存在
样例
输入
8 13
输出
2
说明
高度依次是1,3,6,10,15,.给出的是第4个和第5个子雪面上的高度所以雪的厚度是2
输入
10 15
输出
0
题目分析:
两个柱子的高度差是不变的,高度差就是第二个柱子的序号。因此求得第二个柱子的正常高度再减去当前的高度就是雪的厚度
代码:
python
temp_in = input().split()
a, b = int(temp_in[0]), int(temp_in[1])
d = b-a
result = int(((1+d)*d)/2 - b)
print(result)
二、积木
题目描述
牛牛有一种锯齿状的积木,这种积木比较长,但是每个单位长度的高度是相等的高度为 1 或者 2。
现在牛牛拿出了两块长度分别为n和 m 的积木,她现在想把这两块积木拼接在起,即使中间有空隙也没有关系。
但是拼接后的积木的高度要不超过 3,请你帮助牛牛计算在满足这个前提下拼接后的积木的长度最短可以是多少。
输入描述
第一行给出两个正整数 n,m,代表第一块和第二块积木的长度
第二行给出 n 个数字代表第一块积木每个单位的高度
第三行给出 m 个数字代表第二块积木每个单位的高度 1≤n,m≤10001≤n,m≤1000
输出描述
一个整数,表示拼接后的积木的最短长度
样例
输入
7 10
2212112
2112112112
输出
10
输入
3 2
222
22
输出
5
题目分析:
两个积木拼接起来的最大长度是m+n,核心思想是不可以在同一个位置同时出现'2'。
实现方案是先记录两个字符串中所有'2'的索引为m_2,n_2;我们保持积木n不动,移动m来拼接积木,构建一个record数组,用来存储积木m的头元素可以存在的位置。根据m_2和n_2中的索引,我们可以计算出积木m的头不可以出现的位置,我们将这些位置刨除。最后计算每种情况的拼接长度,保存最小值即可。
但这里存在一个问题,因为该题的背景描述为拼积木,那么默认积木是可以随机翻转的,因此我的代码中包含了翻转的过程。但是实际测评中好像是不翻转(即,翻转代码会导致测评不满分)
代码:
python
temp_in = input().split()
n, m = int(temp_in[0]), int(temp_in[1])
s_n = input().split()[0]
s_m = input().split()[0]
def calc(n, m, s_n, s_m):
result = m+n
m_2 = [idx for idx, c in enumerate(s_m) if c == '2']
for i in range(2):
# 积木n 正向/反向 两种情况
if i == 1:
s_n = s_n[::-1]
n_2 = [idx for idx, c in enumerate(s_n) if c == '2']
# 构造一个m+n+1的空间用来存储本次可以成功拼接的情况
# 字符串n不动,只移动m,记录m的第一个字符的位置
record = [ _ for _ in range(m+n+1)]
for m_i in m_2:
for n_i in n_2:
temp_idx = m + n_i - m_i
record[temp_idx] = -1
# 计算每种拼接情况的总长度
for idx in record:
if idx != -1:
temp_ans = m+n
if idx < m:
temp_ans = max(m, m-idx+n)
else:
temp_ans = max(n, idx)
if temp_ans < result:
result = temp_ans
return result
print(calc(n, m, s_n, s_m))
三、过年
题目描述
牛牛也是要回家过年的呢。
牛牛所在的国家有 n 座城市,m 条有向道路,第 i 条道路由城市ui通往城市vi,通行费为 wi。
作为一头豪气的牛,希望他回家的花费是一个特殊的数字(例如666元)。具体的说,牛牛希望从城市1移动到城市n,并恰好花费a元。
请你告诉牛牛,他有多少种回家的方案?
输入描述
第一行三个整数n,m,a(1≤n≤100,1≤m≤1000,1≤a≤1000),含义如题面所示。 接下来mm行,第ii行三个整数 u_i,v_i, w_i(1 ≤ u_i,v_i \le n,1≤ w_i ≤ a),描述了一条道路。
输出描述
如果牛牛回家的方家数大于等于 20220201种,请你在第一行输出A1l roads lead to Home!,然后在第二行输出回家的方案数对 20220201 取模的结里
否则只需要输出一行一个整数,表示牛牛回家的方案数。
样例
输入
3 6 2
1 2 1
1 2 1
1 2 1
2 3 1
2 3 1
2 3 1
输出
9
说明
从城市一到城市二有3种不同的走法,从城市二到城市三也有3种不同的走法,根据乘法原理我们可以知道,一共有3x3=9种不同的回家方法。
题目分析:
这类计算图中a点到b点有多少种可能性的题目,优先考虑动态规划。本题我们需要考虑一个二维的动态转移数组,dp[i][s],表示到达点i花费为s的方式的数量,这个值如何计算呢?假设我们遍历i的前序节点,其中任一一个节点描述为j,点j到点i的花费为w的路有cnt条,那么我们遍历所有的j和w即可:dp[i][s] = sum(dp[j][s-w]*cnt)。在实际操作中cnt和w可以存在图中,下面代码里我们用了多层dict来描述图的数据结构。
注意:遇到这类题不要上来就dfs或者模拟,通常都不是最优方法,先尝试写一下状态转移方程。
代码:
python
temp_in = input().split()
n, m, a = int(temp_in[0]), int(temp_in[1]), int(temp_in[2])
G = {}
for _ in range(m):
try:
temp_in = input().split()
# 构造G
v, u, w = int(temp_in[0]), int(temp_in[1]), int(temp_in[2])
# G[u][v][w]:表示 从 [v] 点指向 [u] 点花费为 [w] 的路的 【数量】
if u in G.keys():
if v in G[u].keys():
if w in G[u][v].keys():
G[u][v][w] += 1
else:
G[u][v][w] = 1
else:
G[u][v]={w:1}
else:
G[u] = {v:{w: 1}}
except:
break
# print(G)
# for k in G.keys():
# print(k, G[k])
dp = [ [ 0 for _ in range(a+1)] for _ in range(n+1) ]
dp[1][0] = 1
# 转移方程:dp[i][s] += sum(dp[j][s-w] * G[i][j][w]) sum中需要遍历i的每个前序点j的每种花费
for s in range(1, a+1):
for i in range(1, n+1):
if i in G.keys():
for j in G[i].keys():
for w in G[i][j].keys():
if s - w >= 0:
dp[i][s] += dp[j][s-w]*G[i][j][w]
if dp[n][a] >= 20220201:
print("All roads lead to Home!")
dp[n][a] %= 20220201
print(dp[n][a])