一开始看成每个城市只能算一次,然后就愉快的wa了呢。
然后才看到可以反复在两个城市间走。
贪心的想如果m足够大那么最后一定是在两个城市间来回走。
所以我们可以枚举是在哪两个城市间走。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector<ll> vl;
#define PB push_back
#define INFL 0x3f3f3f3f3f3f3f3f
void solve()
{
int n,m,p;
scanf("%d%d%d",&n,&m,&p);
vl pos(n,0ll);
for(auto &i:pos) scanf("%lld",&i);
vl left,right(1,0);//左边的点距原点的距离和右边的点距原点的距离
for(auto i:pos)
{
if(p>=i) left.PB(p-i);
else right.PB(i-p);
}
left.PB(0);
reverse(left.begin(),left.end());
int num_l=left.size()-1,num_r=right.size()-1;
//左边点的个数和右边点的个数
ll minv=INFL;
if(m==1)//特判
minv=min(num_l?left[1]:INFL,num_r?right[1]:INFL);
for(int i=1;i<num_l;i++)//枚举左边的
{
if(i>m) break;
minv=min(minv,left[i]+(m-i)*(left[i+1]-left[i]));
if(i<m&&num_r)
minv=min(minv,left[i]+2*right[1]+(m-i-1)*(left[i+1]-left[i]));
}
for(int i=1;i<num_r;i++)//枚举右边的
{
if(i>m) break;
minv=min(minv,right[i]+(m-i)*(right[i+1]-right[i]));
if(i<m&&num_l)
minv=min(minv,right[i]+2*left[1]+(m-i-1)*(right[i+1]-right[i]));
}
if(num_l&&num_r)//枚举一左一右
{
ll &x=left[1],&y=right[1];
minv=min(minv,min(x,y)+(m-1)*(x+y));
}
printf("%lld\n",minv);
}
int main()
{
int t;
scanf("%d",&t);
while(t--) solve();
return 0;
}

京公网安备 11010502036488号