【问题描述】
小明要搬家了,大家都来帮忙。
小明现在住在第N楼,总共K个人要把X个大箱子搬上N楼。
最开始X个箱子都在1楼,但是经过一段混乱的搬运已经乱掉了。最后大家发现这样混乱地搬运过程效率太低了,于是总结出了提高效率的方法。
大家的速度都是每分钟上(或下)一层楼。所有向上走的人手中都拿一个箱子,所有向下走的人手中都不拿箱子。到达第N层立刻放下箱子向下走,到达第1层立刻拿起箱子向上走。当一个人向上走,另一人向下走而在楼道里相遇时,向上走的人将手中的箱子交给另一人,两人同时反向。即原来拿箱子向上走的人不拿箱子向下走,原来不拿箱子向下走的人现拿着箱子向上走。
求将所有箱子搬完所需的最短时间。
【输入】
第一行N(N≤10^9),K(K≤500000),M(M≤10^9),分别表示楼层数、人数、还放在一楼地上的箱子数。
接下来K行,每行两个数Ai,Bi。
Ai表示第i人现所在的楼层数,Bi为0或1,为0表示第i人正拿着箱子向上走,为1表示第i人不拿箱子向下走。
输入满足没有任意两人正在同一楼层,在第1层的人一定正拿着箱子向上走,在第N层的人一定正不拿箱子向下走。
【输出】
仅包含一个整数,为搬完箱子的时间。
【输入输出样例】
#1
5 2 4
1 0
4 0
#2
20
【分析】
不关心个人“当一个人向上走,另一人向下走而在楼道里相遇时,向上走的人将手中的箱子交给另一人,两人同时反向。”,可以看做仅仅是两人正常走过。如此不难看出2n-2步后,所有人会回到自己原来的位置,同时有k个箱子被放在n层,又有k个箱子在1层被拿走。
走完多次循环直至1层的箱子数小于k时开始模拟(虽然并不是完全暴力)。
如果1层箱子数为0,则再加上最下面一位抬箱子的人到n层的距离。
如果1层箱子数为d(d≠0),则算出所有人再从1层抱一个箱子的总距离,并排序加上第d大的距离。
下面附上代码一份;
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=500100;
long long n,k,m;
long long ans=0;
int a[maxn],b[maxn];
int main()
{
freopen("box.in","r",stdin);
freopen("box.out","w",stdout);
ios::sync_with_stdio(false);
cin>>n>>k>>m;
for(int i=1;i<=k;i++)
cin>>a[i]>>b[i];
ans+=2*(m/k)*(n-1);
m=m%k;
if(m==0)
{
long long pos=n;
for(int i=1;i<=k;i++)
if(b[i]==0&&a[i]<pos)
pos=a[i];
ans+=(n-pos);
cout<<ans<<endl;
}
else
{
for(int i=1;i<=k;i++)
if(b[i]==1) a[i]=a[i]+n-2;
else a[i]=3*n-a[i]-2;
sort(a+1,a+k+1);
ans+=a[m];
cout<<ans<<endl;
}
return 0;
}