P4857 [PA 2013] Konduktorzy

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;
}
posted @ 2025-09-01 16:22  BaiBaiShaFeng  阅读(10)  评论(0)    收藏  举报
Sakana Widget右下角定位