[NERC2019] Apprentice Learning Trajectory 题解
有一个较为简单的贪心策略:每次选取当前能选的、且锻造结束时间最早的一把剑制造。
直接暴力模拟时间复杂度不对,但是考虑到某位大师工作状态变化(开始 / 结束)的时间点最多有 std::set 维护结束时间最早且可以锻造的剑,实现细节较多。时间复杂度
放代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> pii;
typedef tuple<int,int,int> tpi;
main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n,w=0; cin>>n;
vector<int> p(n),ed(n);
vector<tpi> s;
for(int i=0;i<n;i++){
int a,b; cin>>a>>b>>p[i];
s.emplace_back(a,i,1),s.emplace_back(ed[i]=b,i,-1);
} // 把所有事件离线存储
sort(s.begin(),s.end());
// 按照时间点排序
vector<int> tmp(n,-1);
set<pii> m,c;
for(int e=0;e<n<<1;e++){
auto [t,i,k]=s[e];
if(!(e&&get<0>(s[e-1])==t)&&!m.empty()&&m.begin()->first<=t){
w+=1+(t-m.begin()->first)/(c.begin()->first);
// 计算一段时间内能锻造多少把剑
int nt=t-(t-m.begin()->first)%c.begin()->first;
// 求出批量锻造完所有剑后的时刻
while(!m.empty())tmp[m.begin()->second]=-1,m.erase(m.begin());
// 记得清空当前的 set
while(!c.empty()){
auto [x,y]=*c.begin();
if(nt+x>ed[y])c.erase(c.begin());
else{m.emplace(tmp[y]=nt+x,y); break;}
} // 找可用的剑中结束时间最早的
}
if(k==1){
m.emplace(tmp[i]=t+p[i],i);
c.emplace(p[i],i);
} // 加入
else{
if(~tmp[i])m.erase(m.find(make_pair(tmp[i],i)));
c.erase(make_pair(p[i],i));
} // 删除
}
cout<<w<<endl;
return 0;
}