最小得分和

最小得分和·

本 题 一 看 数 据 范 围 就 知 道 大 概 是 O ( n l o g n ) 的 算 法 , 然 后 很 自 然 就 想 到 了 二 分 , 但 关 键 是 怎 么 判 断 本题一看数据范围就知道大概是O(nlogn)的算法,然后很自然就想到了二分,但关键是怎么判断 O(nlogn),
对 于 需 要 原 来 O ( n 2 ) 的 查 找 , 我 们 很 快 就 想 到 了 O ( n ) 优 化 , 具 体 地 , 有 队 列 , 预 处 理 数 组 , 堆 … … 的 优 化 , 这 时 我 们 发 现 , 如 果 我 们 二 分 一 个 最 大 值 我 们 就 可 以 得 到 一 些 快 速 处 理 了 对于需要原来O(n^2)的查找,我们很快就想到了O(n)优化,具体地,有队列,预处理数组,堆……的优化,这时我们发现,如果我们二分一个最大值我们就可以得到一些快速处理了 O(n2)O(n)
这 可 惜 在 比 赛 时 我 没 有 想 到 用 队 列 , 也 没 有 想 到 二 分 后 怎 么 计 算 答 案 这可惜在比赛时我没有想到用队列,也没有想到二分后怎么计算答案

正解

1. 因 为 我 们 二 分 的 是 一 个 最 大 值 满 不 满 足 , 所 以 我 们 先 对 原 数 组 排 序 , 一 遇 到 差 值 小 于 二 分 的 值 的 时 候 , 就 直 接 加 进 队 列 , 一 遇 到 大 于 二 分 的 值 的 时 候 对 首 就 出 队 列 , 这 样 就 可 以 保 证 队 列 里 的 队 尾 一 定 可 以 和 队 列 里 其 它 元 素 一 一 构 成 合 法 方 案 1.因为我们二分的是一个最大值满不满足,所以我们先对原数组排序,一遇到差值小于二分的值的时候,就直接加进队列,一遇到大于二分的值的时候对首就出队列,这样就可以保证队列里的队尾一定可以和队列里其它元素一一构成合法方案 1.

bool check(ll lim){
	ansout=0;cnt=0;
	ll l=1,sum=0;
	for(ll r=1;r<=n;r++)
	{
		while(l<r&&((val[r]-val[l])>lim)) sum-=val[l],l++;//
		ansout+=(r-l)*val[r]-sum;
		sum+=val[r];
		cnt+=(r-l);
	}
	if(cnt>=k) return true;
	return false;
}

2.统计答案的时候,因为最大值小于等于找到的值的数可能有,可能只是个数小于k,所以我们再做一次统计就行了

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll N=1000100;
ll k,n,ansout=0,cnt;
ll val[N];
bool check(ll lim){
	ansout=0;cnt=0;
	ll l=1,sum=0;
	for(ll r=1;r<=n;r++)
	{
		while(l<r&&((val[r]-val[l])>lim)) sum-=val[l],l++;//
		ansout+=(r-l)*val[r]-sum;
		sum+=val[r];
		cnt+=(r-l);
	}
	if(cnt>=k) return true;
	return false;
}
int main(){
	scanf("%lld%lld",&n,&k);
	for(ll i=1;i<=n;i++){
		scanf("%lld",&val[i]);
	}
	sort(val+1,val+n+1);
	ll l=0,r=val[n]-val[1];
	ll ans=r;
	while(l<=r){
		ll mid=((l+r)>>1);
		if(check(mid)) r=mid-1,ans=mid;
		else l=mid+1;
	}
	if(cnt==k){
		printf("%lld",ansout);
		return 0;
	}
	check(ans-1);
	ansout+=(k-cnt)*ans;
	
	printf("%lld",ansout);
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值