CF1996F 题解
考虑 比较小时怎么做。
不难想到每次贪心的取当前 最大的一定是最优的。于是可以用堆来维护当前最大值。
接着考虑 比较大时怎么做。
注意到每次取的 一定是单调不增的,那只要确定最后一个取得值,就能算出最终的答案。
所以考虑二分最后一个取的 ,判断此时取的次数 ,如果 ,那么这个 就是满足的条件。找到最大的 即可。
那怎么求这个 呢?假设二分的值为 ,则 。
最终算答案时就用等差数列求和的方法即可,具体见代码。
#include<bits/stdc++.h>
using namespace std;
int t,n,k,a[200010],b[200010];
bool check(long long mid){
long long sum=0;
for(int i=1;i<=n;i++){
if(a[i]<mid) continue;
long long x=(a[i]-mid)/b[i]+1;
sum+=x;
}
return sum<=k;
}
long long cnt(long long x){
long long sum=0;
for(int i=1;i<=n;i++){
if(a[i]<x) continue;
long long y=(a[i]-x)/b[i]+1;
sum+=y;
}
return sum;
}
long long work(long long x){
long long ans=0;
for(int i=1;i<=n;i++){
if(a[i]<x) continue;
long long l,r,p=(a[i]-x)/b[i];
l=a[i],r=a[i]-p*b[i];
ans+=1ll*(l+r)*(p+1)/2;
}
return ans;
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
long long l=0,r=1e9+1;
while(l<r-1){
long long mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid;
}
if(check(l)) printf("%lld\n",work(l));
else printf("%lld\n",work(r)+max(1ll*(k-cnt(r)),0ll)*l);
}
return 0;
}

浙公网安备 33010602011771号