目录
- 1. 第一题
- 2. 第二题
- 3. 第三题
⏰ 时间:2024/08/17
🔄 输入输出:ACM格式
⏳ 时长:2h
本试卷还有选择题部分,但这部分比较简单就不再展示。
1. 第一题
村子里有一些桩子,从左到右高度依次为 1 , 1 + 2 , 1 + 2 + 3 , . . . 1,1+2,1+2+3,... 1,1+2,1+2+3,...,每两颗桩子之间的间隔为 1 1 1。现在下了一场大雪,但是不知道雪下了多厚,现在给你两个数字,这是雪后某相邻两个桩子在雪面上的高度,请你通过这两个数字计算雪的厚度。
输入描述
在一行中输入两个正整数 a , b a, b a,b, 1 ≤ a < b ≤ 5 ⋅ 1 0 5 1\leq a<b\leq5\cdot10^5 1≤a<b≤5⋅105。
输出描述
在一行中输出一个整数代表雪的厚度。我们可以证明,答案一定存在。
题解
只需注意到 a k − a k − 1 = k a_k-a_{k-1}=k ak−ak−1=k,于是可以用 b − a b-a b−a 定位到右边柱子的下标,计算它的高度即可。
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
i64 a ,b;
cin >> a >> b;
i64 k = b - a;
i64 old_h = k * (k + 1) / 2;
cout << old_h - b << endl;
return 0;
}
2. 第二题
牛牛有一种锯齿状的积木,这种积木比较长,但是每个单位长度的高度是相等的,高度为
1
1
1 或者
2
2
2。
现在牛牛拿出了两块长度分别为
n
n
n 和
m
m
m 的积木,她现在想把这两块积木拼接在一起,即使中间有空隙也没有关系。但是拼接后的积木的高度要不超过
3
3
3,请你帮助牛牛计算在满足这个前提下拼接后的积木的长度最短可以是多少。
例如有两块形状如下的积木:
输入描述
第一行给出两个正整数
n
,
m
n,m
n,m,代表第一块和第二块积木的长度。
第二行给出
n
n
n 个数字代表第一块积木每个单位的高度。
第三行给出
m
m
m 个数字代表第二块积木每个单位的高度
1
≤
n
,
m
≤
1000
1\leq n,m \leq 1000
1≤n,m≤1000。
输出描述
在一行中输出一个正整数代表拼接后积木的最短长度
题解
本题直接模拟即可。
说白了就是给定 a a a 和 b b b 两个数组,初始时先让 a a a 和 b b b 的左端对齐。
- 先让 a a a 在 b b b 上向右滑动,计算两者重叠部分的按位元素和,只要重叠部分中有一个位置出现了 > 3 >3 >3 的情况,说明当前拼接是无效的,继续右移。我们自然是希望 a a a 右移的距离尽可能地小。
- 再让 b b b 在 a a a 上向右滑动,同样是找到正确的拼接位置,并使得 b b b 右移的距离尽可能小。
- 还要考虑一种特殊情况就是无法上下拼接,此时需要将 a a a 和 b b b 直接横向连接,长度为 m + n m+n m+n。
#include <bits/stdc++.h>
using namespace std;
int min_len(const string& a, const string& b) {
int n = a.length(), m = b.length();
// a在b上滑动
for (int i = 0; i < m; i++) {
bool valid = true;
for (int j = i; j < i + n && j < m; j++) {
if (a[j - i] - '0' + b[j] - '0' > 3) {
valid = false;
break;
}
}
if (valid)
return max(m, i + n);
}
return m + n;
}
int main() {
int n, m;
cin >> n >> m;
string a, b;
cin >> a >> b;
cout << min(min_len(a, b), min_len(b, a)) << endl;
return 0;
}
3. 第三题
牛牛也是要回家过年的呢。
牛牛所在的国家有
n
n
n 座城市,
m
m
m 条有向道路,第
i
i
i 条道路由城市
u
i
u_i
ui 通往城市
v
i
v_i
vi,通行费为
w
i
w_i
wi。
作为一头豪气的牛,希望他回家的花费是一个特殊的数字(例如666元)。具体的说,牛牛希望从城市
1
1
1 移动到城市
n
n
n,并恰好花费
a
a
a 元。
请你告诉牛牛,他有多少种回家的方案?
输入描述
第一行三个整数
n
,
m
,
a
(
1
≤
n
≤
100
,
1
≤
m
≤
1000
,
1
≤
a
≤
1000
)
n,m,a\,(1\leq n\leq 100,1\leq m\leq 1000,1\leq a\leq1000)
n,m,a(1≤n≤100,1≤m≤1000,1≤a≤1000),含义如题面所示。
接下来
m
m
m 行,第
i
i
i 行三个整数
u
i
,
v
i
,
w
i
(
1
≤
u
i
,
v
i
≤
n
,
1
≤
w
i
≤
a
)
u_i,v_i,w_i\,(1\leq u_i,v_i\leq n,1\leq w_i\leq a)
ui,vi,wi(1≤ui,vi≤n,1≤wi≤a),描述了一条道路。
输出描述
如果牛牛回家的方案数大于等于
20220201
20220201
20220201 种,请你在第一行输出 All roads lead to Home!
,然后在第二行输出回家的方案数对
20220201
20220201
20220201 取模的结果。
否则只需要输出一行一个整数,表示牛牛回家的方案数。
题解
本题使用动态规划求解。
设 d p [ i ] [ j ] dp[i][j] dp[i][j] 为从城市 1 1 1 到城市 i i i,花费恰好为 j j j 的方案数。由于从 1 1 1 到 1 1 1 花费为 0 0 0,也算是一种方案,因此 d p [ 1 ] [ 0 ] = 1 dp[1][0]=1 dp[1][0]=1,其他地方为 0 0 0。
假设 u → w v u\overset{w}{\to} v u→wv,且在城市 u u u 的时候已经花费了 j j j,那么有如下的转移方程
d p [ v ] [ j + w ] = d p [ u ] [ j ] + d p [ v ] [ j + w ] dp[v][j + w]=dp[u][j]+dp[v][j +w] dp[v][j+w]=dp[u][j]+dp[v][j+w]
注意,在计算 v v v 的时候,我们必须要保证 u u u 已经计算完毕,因此要按照拓扑序进行计算。
#include <bits/stdc++.h>
using namespace std;
const int MOD = 20220201;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m, a;
cin >> n >> m >> a;
vector<vector<pair<int, int>>> graph(n + 1);
vector<int> in(n + 1, 0);
for (int i = 0; i < m; i++) {
int u, v, w;
cin >> u >> v >> w;
graph[u].emplace_back(v, w);
in[v]++;
}
vector<vector<int>> dp(n + 1, vector<int>(a + 1, 0));
vector<bool> st(n + 1, 0);
dp[1][0] = 1;
queue<int> q;
for (int i = 1; i <= n; i++) {
if (!in[i]) q.push(i);
}
while (!q.empty()) {
auto u = q.front();
q.pop();
for (auto &[v, w]: graph[u]) {
if (!--in[v]) q.push(v);
for (int j = 0; j + w <= a; j++) {
if (dp[v][j + w] + dp[u][j] >= MOD || st[u]) {
st[v] = true;
}
dp[v][j + w] = (dp[v][j + w] + dp[u][j]) % MOD;
}
}
}
if (st[n]) cout << "All roads lead to Home!" << endl;
cout << dp[n][a] << endl;
return 0;
}