P10277 [USACO24OPEN] Bessie's Interview S
第一问可以用优先队列模拟,存储每个人的结束时间即可。
第二问,一开始考虑的是对于某一时刻队列中结束时间最小的人是可以任意互换顺序的,所以就用并查集把这些人合在一起。
最后与堆顶元素在同一连通块内的为 1,否则为 0。
然而这样是错误的。
例如,一共有 \(3\) 个人 A,B,C。A,B 在某时刻可交换,且此时选 A 的情况下,B,C 在这之后的某时刻可交换。
考虑 B,C 均面试了一个耗时很长的奶牛,那么最终只有 A 是合法的。同理 B 也是合法的,但 C 不可能合法。
但是并查集做法会说 A,B,C 均合法。
可以参考这个 hack:
7 4
4 4 5 1 2 100 100
我们另辟蹊径。考虑到每个奶牛的面试时间是固定的,所以可以使用 BFS 求解。
初始将 Bessie 压入队列,每次取出一个元素,将结束时间为其起始时间的奶牛压入队列。以此类推,若有奶牛出现在 \(1\sim k\) 内则计入答案。
代码实现没建图,而是使用 set。效果相同。
时间复杂度 \(O(n\log n)\)。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+5;
int n,k,a[N],lp[N],rp[N];
bitset<N> ans;
priority_queue<int,vector<int>,greater<int>> q;
set<int> s;
signed main(){cin>>n>>k;for(int i=1;i<=n;i++) cin>>a[i];for(int i=1;i<=k;i++){rp[i]=a[i];q.push(rp[i]);}for(int i=k+1;i<=n;i++){int t=q.top();q.pop();lp[i]=t,rp[i]=t+a[i];q.push(rp[i]);}cout<<q.top()<<"\n";s.insert(q.top());for(int i=n;i;i--){if(s.count(rp[i])){s.insert(lp[i]);if(i<=k) ans[i]=1;}}for(int i=1;i<=k;i++) cout<<ans[i];return 0;
}