目录
- 1. 第一题
- 2. 第二题
⏰ 时间:2024/08/16
🔄 输入输出:ACM格式
⏳ 时长:1.5h
本试卷还有选择题部分,但这部分比较简单就不再展示。
1. 第一题
题目描述
小明正在神奇苹果园里工作。这个苹果园里一共有 n n n 棵神奇苹果树,编号从 1 1 1 到 n n n,其中编号为 i i i 的苹果树初始有着 a i a_i ai 个苹果,且保证 a i > 0 a_i>0 ai>0。每天小明需要选择其中一棵还有苹果的苹果树上采摘,小明会将其上所有苹果都采摘下来,使得该树上苹果数量归零。采摘完成后,其他所有苹果树会受到惊吓,从而立刻使得它们树上的苹果数量翻倍。小明想要以最优方式采摘,使得最后能收集到的苹果数量最多。请你帮小明找到这样的方案。初始时在第 1 1 1 天,第 i i i 棵树上有 a i a_i ai 个苹果,小明应当选择一颗采摘,而后其余苹果树的苹果数量翻倍,再到第 2 2 2 天循环往复直到第 n n n 天小明采摘完最后一颗非空苹果树。
输入描述
第一行一个整数
n
n
n,表示苹果树数量。
第二行
n
n
n 个整数
a
1
,
a
2
,
⋯
a
n
a_1,a_2,\cdots a_n
a1,a2,⋯an,
a
i
a_i
ai 表示编号为的苹果树初始苹果数量。对于100%的数据,
1
≤
n
≤
50000
1\leq n\leq 50000
1≤n≤50000,
1
≤
a
i
≤
1000000
1\leq a_i\leq 1000000
1≤ai≤1000000。
输出描述
输出一个整数表示答案。因为结果可能较大,请输出结果模100000007的余数。
题解
本题的「采摘完成」指代有些不明确。到底是把一棵树全部采摘完才算采摘完成,还是摘完一个苹果就算采摘完成?(实际上是前者)
显然用贪心算法。要使得最后的苹果数量尽可能地多,应当在一开始采摘苹果数量最小的苹果树,然后采摘次小的,以此类推。我们可以先读入数组然后将其从小到大排个序,设排序后的数组为 { a i } \{a_i\} {ai},那么本题在不求余数的前提下答案为
A n s = ∑ i = 0 n − 1 a i ⋅ 2 i Ans=\sum_{i=0}^{n-1}a_i\cdot 2^i Ans=i=0∑n−1ai⋅2i
由于本题涉及到大数,故用python求解起来会比较方便。但注意到 n n n 的范围可以达到 50000 50000 50000,对于python来讲直接计算 2 50000 2^{50000} 250000 不现实(最多计算到 2 14284 2^{14284} 214284,因为整数长度超过4300无法输出)。只需注意到以下性质
( a i ⋅ 2 i ) m o d x = ( a i ⋅ 2 i m o d x ) m o d x (a_i\cdot 2^i)\,mod\,x=(a_i\cdot 2^i\,mod\,x)\,mod\,x (ai⋅2i)modx=(ai⋅2imodx)modx
n = int(input())
apples = list(map(int, input().split()))
apples.sort()
res = 0
MOD = 100000007
power_of_two = [1] * n
for i in range(1, n):
power_of_two[i] = (power_of_two[i - 1] * 2) % MOD
for i in range(n):
res = (res + apples[i] * power_of_two[i]) % MOD
print(res)
2. 第二题
题目描述
小明正在帮一个工厂规划生产计划。小明已经知道未来 n n n 天工厂会有的情况,初始时机器热量为 0 0 0,如果第 i i i 天启动生产,那么热量会增加 a i a_i ai,产生 b i b_i bi 的收益。若第 i i i 天没有生产,则热量会减少 c i c_i ci。小明知道他应该保证在任何情况下热量都不大于阈值 T T T,否则机器会损坏。小明想知道在最佳规划下,工厂最大能获得多少收益。注意热量最低为 0 0 0,再降温将无效。
输入描述
第一行两个整数
n
n
n 和
T
T
T,表示工厂规划天数和热量阈值。
第二行
3
n
3n
3n 个整数
a
1
,
b
1
,
c
1
,
⋯
,
a
n
,
b
n
,
c
n
a_1,b_1,c_1,\cdots,a_n,b_n,c_n
a1,b1,c1,⋯,an,bn,cn,含义如题面。
对于100%的数据,
1
≤
n
≤
3000
,
1
≤
T
≤
100
,
0
≤
a
i
,
c
i
≤
T
,
0
≤
b
≤
100000
1\leq n\leq3000,\;1\leq T\leq100,\;0\leq a_i,c_i\leq T,\;0\leq b\leq100000
1≤n≤3000,1≤T≤100,0≤ai,ci≤T,0≤b≤100000。
输出描述
输出一个整数表示答案。
题解
用动态规划求解。
设 d p [ i ] [ j ] dp[i][j] dp[i][j] 为第 i i i 天结束时热量为 j j j 时能获得的最大收益。于是可知本题答案为 max j d p [ n ] [ j ] \max_j dp[n][j] maxjdp[n][j] 且 d p [ 0 ] [ 0 ] = 0 dp[0][0]=0 dp[0][0]=0(因为第 0 天,热量为 0 且收益为 0)。
显然遍历方向是 i i i 从小到大, j j j 也从小到大。
第 i i i 天,我们既可以选择生产也可以选择不生产,于是有两个转移方程:
d p [ i ] [ j + a [ i ] ] = m a x ( d p [ i ] [ j + a [ i ] ] , d p [ i − 1 ] [ j ] + b [ i ] ) d p [ i ] [ m a x ( j − c [ i ] , 0 ) ] = m a x ( d p [ i ] [ m a x ( j − c [ i ] , 0 ) ] , d p [ i − 1 ] [ j ] ) dp[i][j + a[i]] = max(dp[i][j + a[i]], dp[i - 1][j] + b[i]) \\ dp[i][max(j - c[i], 0)] = max(dp[i][max(j - c[i], 0)], dp[i - 1][j]) dp[i][j+a[i]]=max(dp[i][j+a[i]],dp[i−1][j]+b[i])dp[i][max(j−c[i],0)]=max(dp[i][max(j−c[i],0)],dp[i−1][j])
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, T;
cin >> n >> T;
vector<int> a(n + 1), b(n + 1), c(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i] >> b[i] >> c[i];
}
vector<vector<int>> dp(n + 1, vector<int>(T + 1, -1));
dp[0][0] = 0;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= T; j++) {
if (dp[i - 1][j] == -1) continue;
if (j + a[i] <= T) {
dp[i][j + a[i]] = max(dp[i][j + a[i]], dp[i - 1][j] + b[i]);
}
int new_j = max(j - c[i], 0);
dp[i][new_j] = max(dp[i][new_j], dp[i - 1][j]);
}
}
int ans = *max_element(dp[n].begin(), dp[n].end());
cout << ans << endl;
return 0;
}