学习C++从娃娃抓起!记录下USACO(美国信息学奥赛)备考青铜组别比赛学习过程中的题目,记录每一个瞬间。
附上汇总贴:USACO历年青铜组真题解析 | 汇总-CSDN博客
【题目描述】
Farmer John 的草地里的草在一场大旱中都干死了。经过数小时的绝望和沉思,Farmer John 想到了一个绝妙的主意,购买玉米来喂养他宝贵的奶牛。
FJ 的 N 头奶牛(1≤N≤10^5)排成一行,队伍中的第 i 头奶牛的饥饿度为 hi(0≤hi≤10^9)。由于奶牛是社会性动物,她们坚持一起进食,FJ 降低奶牛饥饿度的唯一方法是选择两头相邻的奶牛 i 和 i+1 并分别喂她们一袋玉米,令她们的饥饿度各减少 1。
FJ 想将他的奶牛喂至所有的奶牛都具有相同的非负饥饿度。请帮助 FJ 求出他喂奶牛达到上述状态所需的最少玉米袋数,或者如果不可能达到,输出 −1。
【输入】
每个测试用例包含多个独立的子测试用例,必须全部回答正确才能通过整个测试用例。
输入的第一行包含 (1≤T≤100),为你需要求解的子测试用例的数量。
以下是 T 个子测试用例,每个子测试用例包含两行。
第一行包含 N,第二行包含 h1,h2,…,hN。输入保证所有子测试用例的 N 之和不超过 10^5。
每个子测试用例的 N 的值可能不同。
【输出】
输出 T 行,每个测试用例输出一行。
【输入样例】
5
3
8 10 5
6
4 6 4 4 6 4
3
0 1 0
2
1 2
3
10 9 9
【输出样例】
14
16
-1
-1
-1
【代码详解】
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll t, n, a[100005], b[100005];
int main()
{
cin >> t; // 输入t
while (t--) { // 遍历t次循环
ll ans=0; // 定义最少玉米袋数,需使用long long类型
cin >> n; // 输入n
for (int i=1; i<=n; i++) { // 记录n头奶牛的饥饿度
cin >> a[i];
}
if (n==1) { // 特判:如果n为1
cout << 0 << endl; // 输出0,因为此时无需调整
continue;
}
if (n==2 && a[1]!=a[2]) { // 特判:如果n为2,且两头牛饥饿度不一样
cout << -1 << endl; // 输出-1,因为无法调整
continue;
} else if (n==2 && a[1]==a[2]) { // 如果n为2,且两头牛饥饿度一样
cout << 0 << endl; // 输出0,因为无需调整
continue;
}
for (int i=2; i<=n; i++) { // 从第2头牛开始遍历
if (a[i]>=a[i-1]) { // 只要当前牛的饥饿度大于前一头牛
int delta = a[i]-a[i-1]; // 计算两个之间的差值
a[i+1] = a[i+1] - delta; // 下一头牛需要减去这个差值
a[i] = a[i] - delta; // 当前的牛也把饥饿度变的和前一头一样
ans += 2*delta; // ans增加2个差值
i = i+1; // 下次循环i从i+2开始(但这里需设置为i+1,因为还有i++)
}
}
sort(a+1, a+n+1); // 一轮遍历完后进行从小到大的排序
int mark=0; // 定义标记位,准备特判
for (int i=1; i<=n; i++) { // 遍历n头牛
if (a[i]<0) { // 如果其中有小于0的
mark=1; // 则修改mark为1
break; // 退出循环
}
}
if (mark==1) { // 对于一轮遍历调整后小于0的,不符合题意
cout << -1 << endl; // 输出-1
continue;
}
int cnt = 0; // 定义标记位,准备特判
for (int i=2; i<=n; i++) { // 遍历n头牛
if (a[i]>a[i-1]) cnt++; // 如果属于为连续递增
}
if (cnt==n-1) { // 则cnt为n-1
cout << -1 << endl; // 输出-1,因为连续递增的场景无解
continue;
}
int pos = 0; // 定义标记位,准备特判
for (int i=1; i<=n; i++) { // 遍历n头牛
if (a[i]!=a[1]) { // 找到第1头和最小值不同的位置
pos = i;
break;
}
}
if ((n-(pos-1))%2==1) { // 如果除最小值外的牛的数量是奇数,也无法调整
cout << -1 << endl;
continue;
}
for (int i=2; i<=n; i++) { // 遍历n头牛
ans += a[i]-a[1]; // 计算每两头牛的差值,并累加,这个就是要减少的饥饿度总和
}
if (ans%2==1) { // 如果总和是奇数
cout << -1 << endl; // 也是无解的
continue;
} else { // 只有总和是偶数时,总和还是最终的解
cout << ans << endl;
}
}
return 0;
}
【运行结果】
5
3
8 10 5
14
6
4 6 4 4 6 4
16
3
0 1 0
-1
2
1 2
-1
3
10 9 9
-1