这题好玩
首先家和工地在同侧的不用建桥,排掉
然后我们考虑需要建桥的:
∑
i
=
1
n
D
i
=
∑
i
=
1
n
∣
B
−
S
i
∣
+
∣
B
−
T
i
∣
⋯
B为桥的位置
\sum_{i=1}^n D_i=\sum_{i=1}^n |B-S_i|+|B-T_i|\cdots\text{B为桥的位置}
i=1∑nDi=i=1∑n∣B−Si∣+∣B−Ti∣⋯B为桥的位置
如果把家和工地都放在数轴上的点上
所以桥要建到中位数的位置
- 对于k=1, O ( 1 ) O(1) O(1)求出中位数
- 对于k=2,由于桥的存在,数轴上的点分裂成两派,每一派走他们的桥
那么枚这个分裂点,计算两边的最短距离,打擂台得到最小
暴力做法:(5分)
#include<bits/stdc++.h>
#define re register
#define in Read()
using namespace std;
int in{
int i=0,f=1;char ch;
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')ch=getchar(),f=-1;
while(isdigit(ch))i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int NNN=2e5+10;
int k,n,cnt/*记录要过桥的距离*/;
char PP[10],QQ[10];
int dot[NNN],tot;
int confirmed_sum;
inline int get_sum(int l,int r,int mid){
int res=0;
for(re int i=l;i<=r;++i)
res+=abs(dot[mid]-dot[i]);
return res;
}
inline int work1(){
sort(dot+1,dot+tot+1);
return min(get_sum(1,tot,(1+n)>>1),get_sum(1,tot,((1+n)>>1)+1));
}
inline int work2(){
sort(dot+1,dot+tot+1);
int res=2147483647;
for(re int i=1;i<=tot;++i){
res=min(res,min(get_sum(1,i,(1+i)>>1),get_sum(1,i,((1+i)>>1)+1))+
min(get_sum(i+1,tot,(i+tot+1)>>1),get_sum(i+1,tot,((i+tot+1)>>1)+1)));
}
return res;
}
int main(){
k=in,cnt=n=in;
for(re int i=1;i<=n;++i){
scanf("%s",PP);
int a=in;
scanf("%s",QQ);
int b=in;
if(PP[0]^QQ[0])
dot[++tot]=a,dot[++tot]=b;
else confirmed_sum+=abs(a-b),--cnt;
}
int res=0;
if(k==1)res=work1();
if(k==2)res=work2();
res+=confirmed_sum+cnt;
printf("%d\n",res);
return 0;
}
明显不够
考虑使用数据结构——线段树