传送门
A. Alice and Books
时间限制:1秒 空间限制:256MB 输入:标准输入 输出:标准输出
题目描述
Alice 有 n 本书。第 1 本书有 页,第 2 本书有
页,依此类推,第n本书有
页。Alice 做了以下操作:
她把所有的书分成两个非空的堆。因此,每本书最终都会被放在这两个堆中的一个。
Alice 在每个堆中选择编号最大的一本书来阅读。
Alice 非常喜欢阅读。帮助她找出通过将书分成两堆后,她可以阅读的最大总页数。
输入格式
每个测试包含多个测试用例。第一行包含一个整数 t (),表示测试用例的数量。接下来是每个测试用例的描述。
每个测试用例的第一行包含一个整数 n (),表示 Alice 拥有的书的数量。
每个测试用例的第二行包含 n 个整数 (
),表示每本书的页数。
输出格式
对于每个测试用例,输出一个整数,表示 Alice 可以阅读的最大页数。
样例输入
样例输出
思路
无论怎么分堆,编号最大的书一定是会被阅读的;除此之外,还可以阅读剩余书本中页数最多的书
注释
在第一个测试用例中,Alice 可以把第 1 本书放在第一个堆里,把第 2 本书放在第二个堆里。然后她会阅读 页。
在第二个测试用例中,Alice 可以把第 2 本书和第 3 本书放在第一个堆里,把第 1 本书和第 4 本书放在第二个堆里。然后她会从第一个堆中阅读页数最多的第 3 本书,从第二个堆中阅读页数最多的第 4 本书。然后她会阅读 页。
代码
#include <bits/stdc++.h>
using namespace std;
int t, n, a[105];
inline int read() {
int x = 0, f = 1; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int main() {
t = read();
while (t--) {
n = read();
for (int i = 1; i <= n; i++) a[i] = read();
int ans = 0;
for (int i = n - 1; i; i--) ans = max(ans, a[i]);
ans += a[n];
printf("%d\n", ans);
}
return 0;
}
B. New Bakery
时间限制:1秒 空间限制:256MB 输入:标准输入 输出:标准输出
题目描述
Bob 决定开一家面包店。在开业当天,他烤了 n 个可以出售的面包。面包的通常价格是 a 个硬币,但为了吸引顾客,Bob 组织了以下促销活动:
- Bob 选择某个整数 k (
)。
- Bob 以修改后的价格出售前 k 个面包。在这种情况下,第 i 个 (
) 售出的面包的价格是
个硬币。
- 剩下的
个面包以
个硬币的价格出售。
注意,k 可以等于 0。在这种情况下,Bob将以 a 个硬币的价格出售所有面包。
请帮助 Bob 确定通过出售所有 n 个面包可以获得的最大利润。
输入格式
每个测试包含多个测试用例。第一行包含一个整数 t (),表示测试用例的数量。接下来是每个测试用例的描述。
每个测试用例的唯一一行包含三个整数 n , a 和 b (),分别表示面包的数量、面包的通常价格和第一个以修改价格出售的面包的价格。
输出格式
对于每个测试用例,输出一个整数,表示Bob可以获得的最大利润。
样例输入
样例输出
思路
只有当修改后的价格大于修改前的价格才进行价格修改,即
假设前 k 个面包需要修改的价格,为了使利润最大,我们要使 ,但同时,k 也要在
的范围之内,最后得出来的总价格为:
注释
在第一个测试用例中,Bob 最优的选择是 k = 1。然后他将以 5 个硬币的价格卖出一个面包,并以每个 4 个硬币的通常价格卖出三个面包。这样利润将是 5 + 4 + 4 + 4 = 17 个硬币。
在第二个测试用例中,Bob 最优的选择是 k = 5。然后他将所有面包以修改后的价格卖出,获得利润 9 + 8 + 7 + 6 + 5 = 35 个硬币。
在第三个测试用例中,Bob 最优的选择是 k = 0。然后他将所有面包以通常的价格卖出,获得利润 个硬币。
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
int t, n, a, b;
inline int read() {
int x = 0, f = 1; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
signed main() {
t = read();
while (t--) {
n = read(), a = read(), b = read();
int k = min(n, b - a + 1), sum;
if (k < 0) k = 0;
sum = k * (b + 1) - k * (k + 1) / 2 + (n - k) * a;
printf("%lld\n", sum);
}
return 0;
}
C. Manhattan Permutations
时间限制:2秒 空间限制:256MB 输入:标准输入 输出:标准输出
题目描述
我们称排列 p 的曼哈顿值为表达式 的值。
例如,对于排列 [1, 2, 3],曼哈顿值是 |1 - 1| + |2 - 2| + |3 - 3| = 0;对于排列 [3, 1, 2],曼哈顿值是 |3 - 1| + |1 - 2| + |2 - 3| = 2 + 1 + 1 = 4。
给定整数 n 和 k。找到长度为 n 的一个排列 p,使其曼哈顿值等于 k,或者确定不存在这样的排列。
† 一个长度为 n 的排列是一个包含从 1 到 n 的 n 个不同整数的数组。例如, [2, 3, 1, 5, 4] 是一个排列,但 [1, 2, 2] 不是一个排列(2 在数组中出现了两次),并且 [1, 3, 4] 也不是一个排列(n = 3 但数组中有 4)。
输入格式
每个测试包含多个测试用例。第一行包含一个整数 t (),表示测试用例的数量。接下来是每个测试用例的描述。
每个测试用例的唯一一行包含两个整数 n 和 k (),分别表示排列的长度和所需的曼哈顿值。
保证所有测试用例中 n 的总和不超过 。
输出格式
对于每个测试用例,如果没有合适的排列,输出 "No"。否则,第一行输出 "Yes",第二行输出 n 个不同的整数 (
),表示一个合适的排列。
如果有多个解决方案,可以输出其中任何一个。
你可以以任何大小写形式输出答案(例如,"yEs", "yes", "Yes" 和 "YES" 都是正确答案)。
样例输入
样例输出
注释
在第一个测试用例中,排列 [3, 1, 2] 是合适的,其曼哈顿值为 |3 - 1| + |1 - 2| + |2 - 3| = 2 + 1 + 1 = 4。
在第二个测试用例中,可以证明长度为 4 的排列不存在其曼哈顿值为 5 的情况。
在第三个测试用例中,排列 [1, 2, 3, 4, 5, 6, 7] 是合适的,其曼哈顿值为 |1 - 1| + |2 - 2| + |3 - 3| + |4 - 4| + |5 - 5| + |6 - 6| + |7 - 7| = 0。
思路
- 假设最初始的排列为
,任意交换两个
的值,曼哈顿排列都为偶数。
证明:对于任意的 ,交换
和
的值后,曼哈顿值就会变成
- 将首尾对应位置的
的值全部交换之后,曼哈顿值一定是最大的,且最大的曼哈顿值为
所以如果 k 是奇数或者 ,不存在对应的曼哈顿排列,否则存在曼哈顿排列。
如果存在对应的曼哈顿排列,接下来我们再找出对应的曼哈顿排列。
只需要从头开始遍历,如果交换首尾对应元素后曼哈顿值小于 k,则进行交换;否则,如果现有曼哈顿值比 k 小 x,则交换第 位和第
位元素,并且结束遍历。
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 4e5 + 10;
int t, n, k, p[N];
inline int read() {
int x = 0, f = 1; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
signed main() {
t = read();
while (t--) {
n = read(), k = read();
if ((k & 1) || n * n / 2 < k) { puts("No"); continue; }
puts("Yes");
k /= 2;
for (int i = 1; i <= n; i++) p[i] = i;
for (int i = 1; k > 0; i++) {
if (n + 1 - 2 * i <= k) {
swap(p[i], p[n - i + 1]);
k -= n - 2 * i + 1;
} else {
swap(p[i], p[i + k]);
k = 0;
}
}
for (int i = 1; i <= n; i++) printf("%d ", p[i]);
putchar('\n');
}
return 0;
}