学习C++从娃娃抓起!记录下USACO(美国信息学奥赛)备考学习过程中的题目,记录每一个瞬间。
附上汇总贴:USACO备考冲刺必刷题 | 汇总-CSDN博客
【题目描述】
Farmer John的N头奶牛,总是会迷路走到农场上遥远的地方去!他需要你帮助将她们一起赶回来。 农场的草地大体是一块狭长的区域——我们可以将其想象成一条数轴,奶牛可以占据数轴上的任意整数位置。这N头奶牛现在正位于不同的整数位置,Farmer John想要移动她们,使得她们占据N个相邻的位置(例如,位置6、7、8)。
不幸的是,奶牛们现在很困,Farmer John要让她们集中精力听从命令移动并不容易。任意时刻,他只能使得一头处在“端点”(在所有奶牛中位置最小或最大)位置的奶牛移动。当他移动奶牛时,他可以命令她走到任意一个未被占用的整数位置,只要在新的位置上她不再是一个端点。可以看到随着时间的推移,这样的移动可以使奶牛们趋向越来越近。
请求出使得奶牛们集中到相邻位置所进行的移动次数的最小和最大可能值。
【输入】
先输入一个整数N(N<=100000),接下来输入N个数,表示N头奶牛的位置。
【输出】
输出的第一行包含Farmer John需要将奶牛们聚集起来所需进行的最小移动次数。第二行包含他将奶牛聚集起来能够进行的最大移动次数。
【输入样例】
3
4
7
9
【输出样例】
1
2
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n, a[100005], minn=-1e9;
int main()
{
cin >> n; // 输入n
for (int i=1; i<=n; i++) { // 输入n头奶牛的位置
cin >> a[i];
}
sort(a+1, a+n+1); // 按照从小到大排序
// 先判断最小值
if (a[n-1]-a[1]==n-2 && a[n]-a[n-1]>2) minn = 2; // 特判场景1:n-1头牛挤在左边,最后1头在右边,此时最小移动步数为2
else if (a[n]-a[2]==n-2 && a[2]-a[1]>2) minn = 2; // 特判场景2:n-1头牛挤在右边,最后1头在左边,此时最小移动步数为2
else { // 其他场景
for (int i=1, j=1; i<=n; i++) { // 使用双指针,遍历n头牛
while (j<n && a[j+1]-a[i]+1<=n) { // 需要找到j,满足a[j]-a[i]+1==n。如果a[j]-a[i]+1不是刚好等于n,而是a[j]-a[i]+1<n,a[j+1]-a[i]+1>n,移动n-(j-i+1)头奶牛
j++;
}
minn = max(minn, j-i+1); // i到j区间内牛的最大数量j-i+1
}
minn = n - minn; // 再用n减去牛的数量,就是移动的最小数量
}
cout << minn << endl;
int maxn = max(a[n]-a[2], a[n-1]-a[1]) - n + 2; // (a[n]-a[1]+1) - (n-1),即所有位置的数量-牛的数量得到空位的数量
cout << maxn << endl;
return 0;
}
【运行结果】
3
4
7
9
1
2