P4857 [PA 2013] Konduktorzy
一道浪費了我半個下午的題,我否認這是一道綠題,看了題解還是一知半解,最后瘋狂思考想明白了。
題意略,以后都不放了。
我們該怎么做呢。
加入這個 \(n\) 小一些的話用一個優先隊列模擬就可以,但是這個 \(n\) 出奇的大,讓我們不知道該怎么辦了。
我們需要想辦法縮小問題的范圍。
具體該怎么操作呢?
我們如果知道了最終最左的人的位置,我們就可以縮小需要走的范圍了。
所以先通過二分找到可以保證總共次數達到要求的最大的可能位置。
之后我們算出來每個人前一步所在的位置,之后進行模擬就好啦。
代碼如下
點擊查看代碼
#include <bits/stdc++.h>
#define int long long
#define Node pair<long long,long long>
using namespace std;
const int MN=1e6+116;
int n, m, a[MN], ans[MN];
priority_queue <Node,vector<Node>,greater<Node>> q;
bool check(int x){
int t=m;
for(int i=1; i<=n; ++i){
t-=x/a[i];
if(t<0) return false;
}
return true;
}
signed main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin>>m>>n; int l=0, r=0, res;
for(int i=1; i<=n; ++i){cin>>a[i]; r=max(r,a[i]);}
l=r+1, r*=m;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)){
res=mid;
l=mid+1;
}else{
r=mid-1;
}
}
int minr=res;
for(int i=1; i<=n; ++i){
minr=min(minr,max((int)0,(res/a[i]-1)*a[i]));
}
int now=0;
for(int i=1; i<=n; ++i){
now+=minr/a[i];
q.push({minr/a[i]*a[i],i});
}
while(now<m){
Node t=q.top(); q.pop();
ans[t.second]=++now;
t.first+=a[t.second];
q.push(t);
}
for(int i=1; i<=n; ++i) cout<<ans[i]<<' ';
return 0;
}

浙公網安備 33010602011771號