蓝桥杯练习023

194 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

蓝桥杯练习023

七夕礼物

题目描述

七夕节要到了,小明决定给暗恋已久的女神小花送一份大礼。

已知蓝桥商店有 n个玩偶,第 i 个玩偶能给人带来 ai的好感值。

通过打听,小明得知了七夕节当天女神小花的心情值为 t,于是小明决定,从商店购买任意个玩偶使得这些玩偶能带来的好感值和女神小花的心情值最接近。

请你输出这最小的 |心情值-好感值| 。

输入描述

第一行包含两个整数 n,t,其含义如题所述。

接下来一行包含 n 个整数,分别表示 a1,a2,⋯,an。

1≤N≤105,∣ai∣≤104 , 0≤t≤10^9。

输出描述

输出共一行,包含一个整数,表示答案。

输入输出样例

示例 1

输入

5 11
1 2 3 4 5

输出

1

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 128M

代码

//首先连续就想到前缀和,然后分析得对前缀和数组进行尺取法
//其实还有不用尺取法,比如哈希表优化
#include <stdio.h>
#include <stdlib.h>
int cmp_int(const void*_a, const void*_b);//排序函数原型
int main(int argc, char *argv[])
{
    long long t, i, n, pre[100000] = { 0 }, right, left,min;
    int k=0,j=0;
    long long a[100000];
    scanf("%lld %lld", &n, &t);
    for (i = 0; i < n; i++)
        scanf("%lld", &a[i]);
  pre[0]=a[0];
    for (i = 1; i <n; i++)
        pre[i] = a[i] + pre[i - 1];
        qsort(pre, n, sizeof(pre[0]), cmp_int);//如果用qsor()函数只能从0开始
  min=t;
    for (i = left = 0, right = 1; right <n; right++)
    {
        k = 0;
        while (pre[right] - pre[left] > t)//左端点动的条件,称为临界情况
        {left++; k = 1;j=1;}
        if (pre[right] - pre[left] == t)//注意放在后面,因为left会变
        {min = 0;break;}
        if ((t - pre[right] + pre[left] > pre[right] - pre[left - 1] - t) && k == 1)
        {//当右端点刚好跨过时,并且省略了fabs()函数
            if (pre[right] - pre[left - 1] - t<min) 
      min = pre[right] - pre[left - 1] - t;//因为有多个临界情况,所以要比较
        }
    else if(t - pre[right] + pre[left]<min) min=t - pre[right] + pre[left];//同上
    }if(j==0&&right==n-1){//当没有临界情况,就是都小于t。并且“不是因为break”!
      if(pre[0]>0) min=t-pre[n-1];//当第一个是正数,就是全部都买
  else min=t-pre[n-1]+pre[0];}
    printf("%lld", min);
    return 0;
}
int cmp_int(const void*_a, const void*_b)
{
    int*a = (int*)_a; int*b=(int*)_b;
    return *a - *b;
}

蓝桥杯练习024

快速排序

单向扫描

#include<iostream>
using namespace std;

void swap(int arr[],int p,int r){
	int tmp=arr[p];
	arr[p]=arr[r];
	arr[r]=tmp;	
}

int partition(int arr[],int p,int r){
	int pivot=arr[p];//确定主元 
	int sp=p+1;//确定第一个元素  左侧指针 
	int bigger=r;//确定最后一个元素  右侧指针 
	while(sp<=bigger){
		if(arr[sp]<=pivot){//扫描元素小于主元  
			sp++;//左指针右移 
		}else{
			swap(arr,sp,bigger);//扫描元素大于主元 两指针交换 
			bigger--;//右指针左移 
		}
	}
	swap(arr,p,bigger);//将主元放到正确的位置 
	return bigger;
}

void Qsort(int arr[],int p,int r){
	if(p<r){
		int q=partition(arr,p,r);//确定主元 
		Qsort(arr,p,q-1);//对左侧进行排序 
		Qsort(arr,q+1,r);//对右侧进行排序 
	} 
}
int main()
{
	int arr[10]={1,5,3,4,6,78,9,7,11,33};
	Qsort(arr,0,9);
	for(int i=0;i<10;i++)
		cout<<arr[i]<<" ";
	return 0;
}

双向扫描

#include<iostream>
using namespace std;
void swap(int arr[],int p,int r){//交换元素 
	int tmp=arr[p];
	arr[p]=arr[r];
	arr[r]=tmp;
}

int partition(int arr[],int p,int r){
	int pivot = arr[p];
	int left = p+1;
	int right = r;
	while(left<=right){
		while(left<=right&&arr[left]<=pivot)left++;
		while(left<=right&&arr[right]>pivot)right--;
		if(left<=right)
			swap(arr,left,right);
	}	
	swap(arr,p,right);
	return right;
} 

void Qsort(int arr[],int p,int r){
	if(p<r){
		int q=partition(arr,p,r);
		Qsort(arr,p,q-1);
		Qsort(arr,q+1,r);
	}
}

int main()
{
	int arr[10]={1,4,2,3,6,7,1,3,2,2};	
	Qsort(arr,0,9);
	for(int i=0;i<10;i++)
		cout<<arr[i]<<" ";
	return 0;
}

蓝桥杯练习025

归并排序

#include<iostream>
using namespace std;
int helper[10];
void Merge(int arr[],int p,int mid,int r){
	for(int i=0;i<10;i++)
		helper[i]=arr[i];
	int left=p; //左指针 
	int right=mid+1;//右侧指针 
	int cur=p;
	while(left<=mid&&right<=r){
		if(helper[left]<=helper[right]){
			arr[cur++]=helper[left++];
		}else{
			arr[cur++]=helper[right++];
		}
	} 
	while(left<=mid){
		arr[cur++]=helper[left++];
	}
}
void MergeSort(int arr[],int p,int r){
	if(p<r){
		int mid=p+((r-p)>>1);
		MergeSort(arr,p,mid);
		MergeSort(arr,mid+1,r);
		Merge(arr,p,mid,r);
	}
}

int main()
{
	int arr[10]={1,8,9,6,5,4,2,1,2,1};
	MergeSort(arr,0,9);
	for(int i=0;i<10;i++)
		cout<<arr[i]<<" ";
	return 0;
}

查找第k小的数

#include<iostream>
using namespace std;
void swap(int a[],int i,int j){
	int t=a[i];
	a[i]=a[j];
	a[j]=t;
}
int partition(int a[],int p,int r){
	//三点中值法
	int midIndex=p+((r-p)>>1);//中间位置 
	int midValueIndex=-1; //中间值索引
	if(a[p]<=a[midIndex]&&a[midIndex]<=a[r])
		midValueIndex=midIndex;
	else if(a[r]<=a[p]&&a[p]<=a[midIndex])
		midValueIndex=p;
	else 
		midValueIndex=r; 
	swap(a,p,midValueIndex);
	int pivot=a[p];
	int left=p+1;
	int right=r;
	while(left<=right){
		while(left<=right&&a[left]<=pivot)left++;
		while(left<=right&&a[right]>pivot)right--;
		if(left<=right)
			swap(a,left,right);
	}
	swap(a,p,right);
	return right;	
}
int GetK(int a[],int p,int r,int k){
	int q=partition(a,p,r);
	int qk=q-p+1;
	if(qk==k)return a[q];
	else if(qk>k)return GetK(a,p,q-1,k);
	else return GetK(a,q+1,r,k-qk);
}
int main()
{
	int a[6]={1,67,1345,8,2,4};
	cout<<GetK(a,0,5,5);	
	return 0;
} 

蓝桥杯练习026

最小可用id

#include<iostream>
#include<algorithm>
using namespace std;
int find(int arr[],int len){
	sort(arr,arr+len);
	int i=0;
	while(i<len){
		if(i+1!=arr[i])
			return i+1;
		i++;
	}
	return i+1;
}
int find2(int arr[],int n){
	int helper[n+1];
	for(int i=0;i<n;i++){
		if(arr[i]<n+1)
			helper[arr[i]]=1;
	}
	for(int i=1;i<=n;i++){
		if(helper[i]==0)
			return i;
	}
	return n+1;
}

void swap(int arr[],int p,int r){
	int t=arr[p];
	arr[p]=arr[r];
	arr[r]=t;
}
int partition(int arr[],int p,int r){
	int pivot=arr[p];
	int left=p+1;
	int right=r;
	while(left<=right){
		while(left<=right&&arr[left]<=pivot)left++;
		while(left<=right&&arr[right]>pivot)right--;
		if(left<=right)
			swap(arr,left,right);
	}
	swap(arr,p,right);
	return right;
}

int selectK(int arr[],int p,int r,int k){
	int q=partition(arr,p,r);
	int qk=q-p+1;
	if(qk==k)return arr[q];
	else if(qk>k){
		return selectK(arr,p,q-1,k);
	}else
		return selectK(arr,q+1,r,k-qk);
}
int find3(int arr[],int l,int r){
	if(l>r)return l+1;
	int midIndex=l+((r-l)>>1);//中间下标 
	int q=selectK(arr,l,r,midIndex-l+1);//实际中间位置的值 
	int t=midIndex+1;//期望值 
	if(q==t){
		return find3(arr,midIndex+1,r);
	}else{
		return find3(arr,l,midIndex-1);
	}
}	

int main()
{
	int arr[10]={2,3,4,5,6,8,9,10,11,12};
	cout<<find(arr,10)<<endl;
	cout<<find2(arr,10)<<endl;
	cout<<find3(arr,0,10)<<endl;
	return 0;
}

逆序对个数

归并排序求逆序对个数

代码

#include<iostream>
using namespace std;
int ans=0;
int helper[10];
int Merge(int a[],int p,int mid,int r){
	int left=p;
	int right=mid+1;
	int cur=p;
	for(int i=0;i<10;i++)
		helper[i]=a[i];
	while(left<=mid&&right<=r){
		if(helper[left]<=helper[right])
			a[cur++]=helper[left++];
		else{
			a[cur++]=helper[right++];
			ans+=mid-left+1;
		} 
	} 
	while(left<=mid){
		a[cur++]=helper[left++];
	}
} 
void MergeSort(int a[],int p,int r){
	
	if(p<r){
		int mid=p+((r-p)>>1);
		MergeSort(a,p,mid);
		MergeSort(a,mid+1,r);
		Merge(a,p,mid,r);
	}
}
int main()
{
	int a[10]={37,40,48,90,32,5,12,3,44,13};
	MergeSort(a,0,9);
	cout<<ans<<endl;
	for(int i=0;i<10;i++)
		cout<<a[i]<<" ";	
	return 0;
}