NOI导刊2010提高(05) 小明搬家
question
link
solution
首先,我们来分析一下问题。
问题分析:不要去关心某个人。
本题提供两种解法,本质就是个数学题,AK了IMO的大佬就跳过吧
“当一个人向上走,另一人向下走而在楼道里相遇时,向上走的人将手中的箱子交给另一人,两人同时反向。”,可以看做仅仅是两人正常走过。如此不难看出2n-2步后,所有人会回到自己原来的位置,同时有k个箱子被放在n层,又有k个箱子在1层被拿走。
所以前 (m div k)k 个箱子的搬运时间就等于 (m div k)(2n-2)。 然后考虑剩下的箱子。此时所有人都回到了初始状态。由于初始状态中某些人正在运输 物品(这些物品是不算到 M 里面的),所以可以先让这些人把自己的箱子运输完。
分析时先假设所有人都一起搬了整数趟回到原来位置,然后若刚好搬完则把这些时间加上所有人中距楼顶所需时间最大的人的时间(向下时时间为负数),没有正好搬完 则从最小时间开始依次再加一趟,然后再取最长的时间。
此时剩下的箱子数为 m mod k。对于每个人我们可以计算出其搬运一个箱子所需的时 间,那么我们只需将这些时间排序,第 m mod k 个时间就是所有搬运完成的时间。
上代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 long long N,K,M; 4 struct ren 5 { 6 long long louceng; 7 int shangxia; 8 long long pianli; 9 }r[500005]; 10 bool cmp(ren a,ren b) 11 { 12 return a.pianli<b.pianli; 13 } 14 int main() 15 { 16 scanf("%lld%lld%lld",&N,&K,&M); 17 for(int i=1;i<=K;i++) 18 { 19 scanf("%lld%lld",&r[i].louceng,&r[i].shangxia); 20 if(r[i].shangxia) 21 r[i].pianli=r[i].louceng-1+N-1; 22 else 23 r[i].pianli=N-r[i].louceng+2*(N-1); 24 } 25 sort(r+1,r+K+1,cmp); 26 long long yushu=M%K; 27 if(yushu) 28 { 29 printf("%lld",2*(N-1)*(M/K)+r[yushu].pianli); 30 return 0; 31 } 32 printf("%lld",2*(N-1)*(M/K-1)+r[K].pianli); 33 return 0; 34 }
解法②:
二分答案,因为如果X时间内能完成, X+1时间肯定也能完成
二分将箱子都搬到楼顶的最小时间,考虑如何验证呢?
对于每个人考虑他在X时间内最多能将多少个箱子搬到楼顶,那么首先将这个人移动到 楼顶,分为两种情况:
如果这个人正搬箱子在上楼,则首先让他爬上楼顶减去这一段时间,再去除以2(n-1),求得他 最多能搬多少个箱子到楼顶。
如果这个人空手正在往下走,则让他退回到楼顶,给他加上退回去的时间,再除以2(n-1)
最后统计K个人总共能在X时间内,从一楼搬箱子到楼顶的数量总和是否 >= m ?
上代码
#include <bits/stdc++.h> using namespace std; template<typename T> void read(T &dig) { char c = getchar(); bool flag = false; dig = 0; while(isspace(c)) c = getchar(); if(c == '-') flag = true,c = getchar(); while(isdigit(c)) { dig = (dig << 3) + (dig << 1) + c - '0'; c = getchar(); } if(flag) dig = -dig; return; } template<> void read(char &c) { do { c = getchar(); } while(isspace(c)); return; } void reads(char s[]) { char c; do { c = getchar(); } while(isspace(c)); s[0] = c; for(int i = 1;i;i ++) { c = getchar(); if(isspace(c)) { s[i] = '\0'; break; } s[i] = c; } return; } long long p[500005]; const long long inf = 1ll << 60; int main(void) { long long n,m,k,t,typ,l,r,med,tot; read(n); read(k); read(m); if(n == 1) { printf("0\n"); return 0; } else if(n == 0) { printf("Error\n"); return 0; } else if(k == 0) { printf("inf\n"); return 0; } l = 0; for(int i = 0;i < k;i ++) { read(t); read(typ); if(typ == 0) { p[i] = n - t; l = max(l,p[i]); } else { p[i] = n + t - 2; m --; } } if(m <= 0) { printf("%lld\n",l); return 0; } typ = (n - 1) << 1; r = inf; while(l <= r) { med = (l + r) >> 1; tot = 0; for(int i = 0;i < k;i ++) { tot += (med - p[i]) / typ; } if(tot >= m) r = med - 1; else l = med + 1; } printf("%lld\n",l); return 0; }