牛客小白月赛37 加减-I
题目描述
思路:
假设出现次数最多的元素的次数为 q
二分答案,不难发现 当 q 为一时 ,一定符合
而题目求最大的 q ,当 q 一路增加时 会遇到一个分界点 x ,x左边的值都符合,右边的值都不符合
二分答案
设左端点的值为1,右端点的值为数组的长度
判断函数:
int Abs(int n){
return n<0?n*-1:n;
}
bool is(int q,int nums[],int len,int k){
for(int i=1;i+q-1<=len;i++){
int mid=(i+1+q-1)/2;//目标值的下标
int cont=0;//需要加减的次数
for(int o=i;o<=i+q-1;o++){
cont+=Abs(nums[o]-nums[mid]);//当前值变成目标值需要加减几次
}
if(cont<=k){//如果加减的次数小于等于k次,说明方案是可行的,直接返回true
return true;
}
}
return false;
}
主函数:
#include <bits/stdc++.h>
using namespace std;
int main(){
int len,k;
int sum[100010]={0};
cin>>len>>k;
for(int i=1;i<=len;i++) cin>>sum[i];
sort(sum+1,sum+len+1);
int l=1,r=len+1;
while(l<=r){
int mid=(l+r)/2;
if(is(mid,sum,len,k)){
l=mid+1;
}else{
r=mid-1;
}
}
cout<<r;
return 0;
}
最终结果为超时
只通过了 50%
优化判断函数:
因为我们给数值排过序,目标值是中间值 所以不难发现中位数靠左的都是加一,中位数靠右的都是减一
所以预处理前缀和我们可以把判断函数里的求次数变成 O(1) 的复杂度
优化之后判断函数:
bool is(int q, int nums[], int len,int k,int sum[]) {
for(int i=1;i+q-1<=len;i++){
int mid = (i+i+q-1)/2;//中间的下标
int cont=0;//需要加减的次数
//目标值乘区间长度 减去 区间和 为相加的次数
cont+= nums[mid]*(mid-i+1)-(sum[mid]-sum[i-1]);//左边的次数和
//右边区间总和 减去 目标值乘区间长度 为右边相减的次数
cont+= sum[i+q-1]-sum[mid]-nums[mid]*(i+q-1-mid);//右边的次数和
//如果需要加减的次数符合就返回true
if(cont<= k){
return true;
}
}
return false;
}
运行结果:
看数据范围为 1e9 ,int 存不下,int 替换为 long long 之后满分
代码:
#include <bits/stdc++.h>
using namespace std;
bool is(long long q, long long nums[], long long len,long long k,long long sum[]) {
for(long long i=1;i+q-1<=len;i++){
long long mid = (i+i+q-1)/2;//中间的下标
long long cont=0;//需要加减的次数
//目标值乘区间长度 减去 区间和 为相加的次数
cont+= nums[mid]*(mid-i+1)-(sum[mid]-sum[i-1]);//左边的次数和
//右边区间总和 减去 目标值乘区间长度 为右边相减的次数
cont+= (sum[i+q-1]-sum[mid])-nums[mid]*(i+q-1-mid);//右边的次数和
//如果需要加减的次数符合就返回true
if(cont<= k){
return true;
}
}
return false;
}
int main(){
long long len,k;
long long nums[100010]={0};
long long sum[100010]={0};//前缀和
cin>>len>>k;
for(long long i = 1;i <= len;i++) cin>>nums[i];
sort(nums+1, nums+1+len);
for(long long i=1;i<=len;i++) sum[i]=sum[i-1]+nums[i];
long long l=1,r=len+1;
while(l<=r){
long long mid=(l+r)/2;
if(is(mid, nums, len, k,sum)){
l=mid+1;
}else{
r=mid-1;
}
}
cout<<r;
return 0;
}