题面
数轴上有 n 栋楼,第 i 栋楼位于 xi,住了 ai 个人。现在这些人都在 S,要搭车回家。
乘车时,每一时刻,车上所有人投票决定向正方向走还是向负方向走,少数服从多数(同票则往负方向走)。每个人都按照自己尽早回家的策略投票。如果到了一栋房子门口,这里所有人都会下车。求最晚回家的人回家的时间。
n≤105。
题解
『自己尽早回家』真的等同于『每次投自己家的方向』吗?
对于上面的问题,考虑 1,3,4 位置有房子,分别有 3,4,2 个人,所有人最开始在 2。对于住在 4 的人,如果他们投右边,则住在 3 的人中途下车后,这些人就投不过住在 1 的人了。因此会多绕路。
把这个实例形式化描述为:对于家住两端的人(设为 xl,xr),不妨设 al<ar,此时住在 xl 的那些人会选择投右边,避免多绕路。
对于这种情况,不妨认为这些人直接“搬家”到 xr 住,最后强制对答案加上一个车走回来的路程 xr−xl 即可。题目转化成了原问题的子问题。可以递归求解。递归边界为初始位置不在当前考虑的区间内,此时所有人都会投同一个方向。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| #include<bits/stdc++.h> #define int long long using namespace std; bool Begin; const int max_n=100005; inline int read(){ int x=0;bool w=0;char c=getchar(); while(c<'0' || c>'9') w|=c=='-',c=getchar(); while(c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return w?-x:x; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10^48); }
int n,S,x[max_n],a[max_n];
inline int sol(int l,int r,int dir){ if(S<x[l]) return x[r]-S; if(S>x[r]) return S-x[l]; if(a[l]>=a[r]){ a[l]+=a[r]; return sol(l,r-1,1)+(dir==1?0:(x[r]-x[l])); } a[r]+=a[l]; return sol(l+1,r,-1)+(dir==-1?0:(x[r]-x[l])); }
bool End; #define File "" signed main(){ n=read(),S=read(); for(register int i=1;i<=n;++i) x[i]=read(),a[i]=read(); write(sol(1,n,a[1]>=a[n]?-1:1)); return 0; }
|