NC14844 codeJan与旅行
题目地址:
基本思路:
基本思路就是贪心,关键点是我们不走回头路,也就是说我们要么一直往左走,要么一直往右走,然后在每个位置我们都有可能开始左右横跳来回重复走。(这部分可以看其他大佬的证明,或者自己脑补证明一下,这里就不长篇幅证明了QAQ)。因为开始重复走之后需要走的距离是能O(1)立马算到的,所以我们从左右两边枚举,然后将在每个位置开始横跳得到的最终答案都算出来,然后取最小值就是了。
参考代码:
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define IO std::ios::sync_with_stdio(false)
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define per(i, l, r) for (int i = l; i >= r; i--)
#define mset(s, _) memset(s, _, sizeof(s))
#define pb push_back
#define pii pair <int, int>
#define mp(a, b) make_pair(a, b)
#define INF (int)1e18
inline int read() {
int x = 0, neg = 1; char op = getchar();
while (!isdigit(op)) { if (op == '-') neg = -1; op = getchar(); }
while (isdigit(op)) { x = 10 * x + op - '0'; op = getchar(); }
return neg * x;
}
inline void print(int x) {
if (x < 0) { putchar('-'); x = -x; }
if (x >= 10) print(x / 10);
putchar(x % 10 + '0');
}
const int maxn = 1e5 + 10;
int n,m,p;
int a[maxn];
int solve(int now){
int ans = INF,sum = abs(a[now] - p) ,z = m - 1;
if(z == 0) return sum;
//一直往右走的情况;
for(int i = now + 1; i <= n && z > 0; i++,z--){
int tmp = abs(a[i] - a[i-1]);
ans = min(ans,tmp * z + sum);//从这个位置开始重复来回走,直到走完;
sum += tmp;//这里不开始横跳,就要把这部分走的距离加上;
}
sum = abs(a[now] - p) ,z = m - 1;
//一直往左走的情况;
for(int i = now - 1; i >= 1 && z > 0;i--,z--){
int tmp = abs(a[i+1] - a[i]);
ans = min(ans,tmp * z + sum);//从这个位置开始重复来回走,直到走完;
sum += tmp;//这里不开始横跳,就要把这部分走的距离加上;
}
return ans;
}
signed main() {
IO;
int t;
cin >> t;
while(t--){
cin >> n >> m >> p;
rep(i,1,n) cin >> a[i];
int now = lower_bound(a+1,a+1+n,p) - a;
//可以从初始位置左边或右边的城市开始,所以两种情况都要算;
int ans = solve(now);
if(now - 1 >= 1) now--;
ans = min(ans,solve(now));
cout << ans << '\n';
}
return 0;
}
京公网安备 11010502036488号