题目链接
题目解法
在同一边的情况一定不会过桥,可以直接算出来
这里只考虑不在同一边的情况,一定需要过一次桥
发现家和办公室的位置可以互换,下面假设家在A岸,办公室在B岸(其实没什么用)
- 首先考虑 k=1 的情况,如果家在 a 处,办公室在 b 处,桥在 p 处
那么从家到办公室的距离就是 ,其中 +1 可以提前计算,这里不考虑可以发现,a 和 b 对 p 的贡献可以分开算,就是它们到 p 的距离题意可以抽象成,有一些点,询问位置 p ,使得 p 到这些点的距离之和最小
p 显然取中位数最优 - 考虑 k=2 的情况,我们希望能将居民分成 2 部分,使得第一部分和第二部分都转化为 k=1 的情况
我们发现有 2 个桥的情况,走离 的桥更优
这里画个图,分类讨论一下就比较显然了
可以发现这里满足排序贪心的性质
如果有桥 p1, p2(p1<p2),居民 a1, b1, a2, b2(a1+b1<a2+b2)
如果居民1走桥 p2,那么居民2一定走桥p2
反之也成立
我们发现可以枚举断点,断点左边都走左边的桥,断点右边都走右边的桥
这里需要动态维护中位数,用对顶堆即可
#include <bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> pii;
const int N(100100),inf(1e18);
int k,n,ans,sum[N<<1];
int nums[N<<1];
pii a[N];
int t1[N],t2[N];
int siz1,siz2,sum1,sum2;
priority_queue<int> que1;
priority_queue<int,vector<int>,greater<int> > que2;
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar())
if(ch=='-')
RR=-1;
for(;isdigit(ch);ch=getchar())
FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
void solve1(){
for(int i=1,s,t;i<=n;i++){
char p[2],q[2];
scanf("%s",p);s=read();scanf("%s",q);t=read();
if(p[0]!=q[0]) nums[(i<<1)-1]=t,nums[i<<1]=s;
else ans+=abs(t-s),i--,n--;
}
sort(nums+1,nums+(n<<1)+1);
int pos=nums[n];
for(int i=1;i<=n<<1;i++)
ans+=abs(nums[i]-pos);
printf("%lld",ans+n);
}
bool cmp(const pii &x,const pii &y){
return x.first+x.second<y.first+y.second;
}
void insert(int x){
if(que1.empty()||x<=que1.top()) que1.push(x),siz1++,sum1+=x;
else que2.push(x),siz2++,sum2+=x;
}
void balance(){
while(siz1<siz2){
int t=que2.top();
que1.push(t),siz1++,sum1+=t;
que2.pop(),siz2--,sum2-=t;
}
while(siz1-1>=siz2+1){
int t=que1.top();
que2.push(t),siz2++,sum2+=t;
que1.pop(),siz1--,sum1-=t;
}
}
void solve2(){
for(int i=1,s,t;i<=n;i++){
char p[2],q[2];
scanf("%s",p);s=read();scanf("%s",q);t=read();
if(p[0]!=q[0]) ans++,a[i]=make_pair(s,t);
else ans+=abs(t-s),i--,n--;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++){
insert(a[i].first),insert(a[i].second);
balance();
t1[i]=que1.top()*siz1-sum1+sum2-que1.top()*siz2;
}
while(!que1.empty()) que1.pop();
while(!que2.empty()) que2.pop();
siz1=siz2=sum1=sum2=0;
for(int i=n;i>=1;i--){
insert(a[i].first),insert(a[i].second);
balance();
t2[i]=que1.top()*siz1-sum1+sum2-que1.top()*siz2;
}
int ans2=inf;
for(int i=0;i<=n;i++)
ans2=min(ans2,t1[i]+t2[i+1]);
printf("%lld",ans+ans2);
}
signed main(){
k=read(),n=read();
if(k==1) solve1();
else solve2();
return 0;
}