【題解】JOISC2017 手持ち花火(Sparklers) | 20211106 模擬賽 你還沒有導光嗎(light)【二分 貪心】
阿新 • • 發佈:2021-11-06
題意
數軸上有 \(n\) 個人,每人手持一根菸花棒,一根菸花棒只能被點燃一次,燃燒 \(t\) 秒。初始第 \(k\) 個人手上的煙花棒剛剛點燃,隨後所有人開始移動;當兩人位置重疊且其中一個人的煙花棒還在燃燒時,一個人可以用自己的煙花棒點燃另一個的,耗時不計。現在希望每個人的煙花棒都被點燃過,問全程所有人最大速度的最小值。\(n\leq 10^5\)
題解
首先二分。我們注意到以下性質:
- 一個人其實可以一直全速奔跑;
- 如果有兩人同時有燃著的煙花棒,其實可以讓一個人在煙花棒燃盡時再點燃另一個的,因此同一時間只有一個煙花棒被點燃;
- 所有人都往煙花棒所在位置跑,大部分人的相對位置不變。
因此我們需要做若干次決策,形如當前煙花棒燃著的人(或者說與他位置重疊的一群人)往左跑還是往右跑,一次決策會讓煙花燃燒的剩餘時間減一定值再加 \(t\)。
把往左往右的決策放入兩個佇列,每次我們會把隊首儘可能短但總收益為正的一段合併起來,在左右之間任選一個可行的這樣的段。如果這樣的段清空不了則不合法。還有些元素沒有被合併到段裡,我們倒著做這個過程(即先算出結束時煙花棒的剩餘時間,再把整個過程逆序做一遍)。
#include<bits/stdc++.h> using namespace std; vector<int>vl,vr; int n,k,t; double len; pair<vector<pair<double,double>>,vector<pair<double,double>>> split(vector<int>v,double x){ vector<pair<double,double>>vl; double co=0,get=0; int u=-1; for(int i=0;i<v.size();i++){ get-=v[i]/x/2; co=max(co,-get); get+=t; if(get>=0){ vl.emplace_back(co,get); u=i; co=0;get=0; } } co=0;get=0; vector<pair<double,double>>vr; int uu=v.size(); for(int i=v.size()-1;i>u;--i){ get-=t; co=max(co,-get); get+=v[i]/x/2; if(get>=0){ vr.emplace_back(co,get); uu=i; co=0;get=0; } } if(uu!=u+1)return {{{1e9,0}},{{1e9,0}}}; return make_pair(vl,vr); } bool check(vector<pair<double,double>>v1,vector<pair<double,double>>v2,double t0){ double cur=t0; int u=0,v=0; while(u<v1.size()||v<v2.size()){ if(u<v1.size()&&cur>=v1[u].first)cur+=v1[u++].second; else if(v<v2.size()&&cur>=v2[v].first)cur+=v2[v++].second; else return false; } return true; } bool check(double x){ auto vll=split(vl,x); auto vrr=split(vr,x); return check(vll.first,vrr.first,t)&&check(vll.second,vrr.second,t*1.*n-len/x/2); } int main(){ ios::sync_with_stdio(0); cin.tie(0); cin>>n>>k>>t; int lst=0;cin>>lst; for(int i=1;i<k;i++){ int x;cin>>x; vl.push_back(x-lst); lst=x; } for(int i=k;i<n;i++){ int x;cin>>x; vr.push_back(x-lst); lst=x; } len=lst; if(lst==0)return cout<<0,0; reverse(vl.begin(),vl.end()); int l=0,r=1e9,ans=0; while(l<=r){ int mid=(l+r)/2; if(check(mid))r=mid-1,ans=mid; else l=mid+1; } cout<<ans<<endl; }
若文章內無特別說明,公開文章採用知識共享署名-相同方式共享 4.0 國際許可協議進行許可。