CF1996F 题解

考虑 kk 比较小时怎么做。

不难想到每次贪心的取当前 aia_i 最大的一定是最优的。于是可以用堆来维护当前最大值。

接着考虑 kk 比较大时怎么做。

注意到每次取的 aia_i 一定是单调不增的,那只要确定最后一个取得值,就能算出最终的答案。

所以考虑二分最后一个取的 aia_i,判断此时取的次数 xx,如果 xkx\le k,那么这个 xx 就是满足的条件。找到最大的 xx 即可。

那怎么求这个 xx 呢?假设二分的值为 ee,则 x=i=1n(aiebi+1)x=\sum^n_{i=1}(\lfloor\frac{a_i-e}{b_i}\rfloor+1)

最终算答案时就用等差数列求和的方法即可,具体见代码。

#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;
}
posted @ 2024-07-28 11:08  fengxiaoyi  阅读(21)  评论(0)    收藏  举报  来源