Wooden Toy Festival 题解:二分答案与贪心验证
题意:
有三个雕刻师,他们需要制作n个玩具,对于n个玩具,每个玩具都有一个图案值a[i],
如果雕刻师选择的图案是 x ,那么为他制作一个图案为 y 的玩具需要 |x−y| 的时间,因为玩具越像他能立即制作的玩具,雕刻师的工作速度就越快。
雕刻师们都是非常熟练的人,可以同时处理不同玩具 雕刻师们希望在选择准备工作的样式时,尽可能减少完成制作所有玩具所需要的等待时间
要求你求出制作出所有玩家所需要的最短等待时间
分析
当需要求某个数是最大值/最小值的时候,会考虑到问题是否可以通过二分搜索来解决。
能用二分搜索解决的问题通常具有单调性,而对于本题,很明显的一个事实是如果等待时间越短,那么三个雕刻师一开始所选择的图案就与越多的玩具的a[i]相似.。
而且,还注意到,如果3个雕刻师能够在 t 的时间内制作所有的玩具,那么3个雕刻师必定也能在 d (d > t) 的时间内也制作所有的玩具
因此我们可以尝试二分搜索可行的时间(即三个雕刻师是否可以在这个时间内把所有的玩具制作完),一旦查到可行的时间,我们便试着不断缩小搜索的区间去把mid值逼近最优解。
条件判断
那么现在的问题是该如何判断三者可以在时间 t 内制作所有玩具?
想象一下,如果我们给三个雕刻师分别分配任务,时间 t 实际上取决于三者之间最晚完成任务的人。 考虑到任务分配的顺序是没有影响的,那么我们最好对图案数组先排序一次,因为排序后的数组中对于 任意的 (i, j),他们的 |a[i] - a[j]| 的值总要比未排序的要小。
也就是因为这个排序后的性质,如果我们在排序后的数组里面按顺序分配任务,选定 i,某个雕刻师在 t 时间内能制作完成的玩具数量即为在 [a[i], a[i] + 2*x] 值区间内的 a[i] 的数量
所以剩下来的部分就只有模拟了,我们模拟分配工作给雕刻师,记录当前已完成制作的玩具的数量 cur,每名雕刻师的工作完成后cur都会增加,而这个cur后面的玩具又会交给下一个雕刻师,最后检查cur是否到达n个数量即可
详细代码
#include <bits/stdc++.h>using namespace std;
const int mod = 1e6+10;typedef long long ll;#define x first#define y secondtypedef pair<int, int> P;
ll v[mod];ll n;
bool check(ll x) { int cur = 0; for (int i = 0; i < 3; ++i) { int start = v[cur]; int end = start + 2 * x; while (cur < n && v[cur] <= end) { ++cur; } if (cur >= n) { return true; } }
return cur >= n;}
void solve() { cin >> n;
for (int i = 0; i < n; i++) { cin >> v[i]; }
sort(v, v+n);
ll l = 0, r = 1e9; ll mid,ans=1e9; //mid为三者雕刻所需要的最大时间 //check的时候,尽可能多的在mid时间内为雕刻师安排多的v //显然这个问题具有单调性,如果用时越久,模具的制作偏差就越大 while (l <= r) { mid=(l+r)>>1; if (check(mid)) { r = mid-1; ans = mid; } else { l = mid+1; } } cout << ans << endl;}
int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
int t; cin >> t; while(t--) solve();
return 0;}文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!











