我哭了, 一大早起床本来想做个题后写作业, 结果被这道题搞了几个小时满脑子都是乱的还做不出来, 跑去看了题解
Solution
大致思想其实挺好想的(注意!是大致!) 因为题目保证不会存在 与城市节点重合的情况
我们先处理出 左右两个城市的位置(注意一下边界的处理)
然后很显然的, 我们可以找到从当前位置去到两个距离小的城市进行反复移动
令 为
到所枚举城市的距离,
为还需要访问多少个城市,
为到枚举点途径的城市数
有 , 最终结果就是
, 其中
为所枚举的终点城市
设移动到左边最近城市后枚举为方案1, 移动到右边最近城市后枚举为方案2
比较两个方案的 大小即可
这道题就做完了......吗?
其实没有!
因为会存在两种情况可能更优, 先往左走一个城市, 再往右边最近城市, 此时再做方案2
或者先往右走一个城市, 再往左边最近城市, 此时在做方案1
这里也是看了 聚聚的题解才知道
比如数据
1
3 10 2
1 10 14
答案是42
此时就会出现上面的情况
Code
/*
autor: Kurisu
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const long long inf = 1e18;
const int N = 1e6 + 5;
const double eps = 1e-10;
const ll mod = 1e9 + 7;
ll sum[N], a[N];
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n, m, p;
cin >> n >> m >> p;
int pos = 0;
for(int i = 1; i <= n; i++) {
cin >> a[i];
if(a[i] < p) pos = i;
}
ll ans = 1e18;
for(int i = 1; i < n; i++) {
if(i <= pos) { // 往左走
if(pos - i + 1 > m) continue;
ll num = m - (pos - i + 1), dist = p - a[i];
ans = min(ans, dist + num * (a[i + 1] - a[i]));
if(num > 0 && pos + 1 <= n) { // 先往右走一格, 再往左走
ans = min(ans, (a[pos + 1] - p) * 2 + dist + (num - 1) * (a[i + 1] - a[i]));
}
} else { // 往右走
if(i - pos > m) continue;
ll num = m - (i - pos), dist = a[i] - p;
ans = min(ans, dist + num * (a[i + 1] - a[i]));
if(num > 0 && pos >= 1) { // 先左走一格 再往右走
ans = min(ans, (p - a[pos]) * 2 + dist + (num - 1) * (a[i + 1] - a[i]));
}
}
}
cout << ans << "\n";
}
return 0;
} 
京公网安备 11010502036488号