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号