一开始看成每个城市只能算一次,然后就愉快的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; }