BZOJ3735 : [Pa2013]Konduktorzy

二分一个最大的位置$x$,计算$t=\sum_{i=1}^k\lfloor\frac{x}{a_i}\rfloor$。

如果$t\leq n$,那么说明就算全部检票员都走到了这里,也不够$n$个指令,所以可以先将所有检票员尽量向$x$位置走,并将用掉的指令数扣除。

然后将$x$适当往前调整,使得每个检票员还差至少一步。

因为$a_i$互不相同,并且$a_i\leq 100000$,所以剩余指令数并不多,用堆直接模拟即可。

时间复杂度$O(k\log^2k)$。

 

#include<cstdio>
#include<algorithm>
#include<queue>
#define N 100010
using namespace std;
typedef long long ll;
typedef pair<ll,int> P;
int n,i,a[N];ll m,L,R,mid,fin,now,ans[N];priority_queue<P,vector<P>,greater<P> >Q;
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
bool check(ll x){
  ll t=m;
  for(int i=1;i<=n;i++){
    t-=x/a[i];
    if(t<0)return 0;
  }
  return 1;
}
int main(){
  scanf("%lld",&m);read(n);
  for(i=1;i<=n;i++){
    read(a[i]);
    if(a[i]>R)R=a[i];
  }
  L=R+1,R*=m;
  while(L<=R)if(check(mid=(L+R)>>1))L=(fin=mid)+1;else R=mid-1;
  for(R=fin,i=1;i<=n;i++)R=min(R,max((fin/a[i]-1)*a[i],0LL));
  for(i=1;i<=n;i++)now+=R/a[i],Q.push(P(R/a[i]*a[i],i));
  while(now<m){
    P t=Q.top();Q.pop();
    ans[t.second]=++now;
    t.first+=a[t.second];
    Q.push(t);
  }
  for(i=1;i<n;i++)printf("%lld ",ans[i]);printf("%lld",ans[n]);
  return 0;
}

  

你可能感兴趣的:(BZOJ3735 : [Pa2013]Konduktorzy)