【题解】数糖果

题目

题目描述

Alice和Bob现在有n堆糖果(n为偶数)。由于Alice喜欢平方数,但Bob不喜欢,因此,他们决定通过一些操作,使得这n堆糖果恰好有n/2堆里的糖果数为平方数,另外n/2堆不是平方数。而对于每一次操作,他们只能从其中某一堆糖果当中,取出或放入一颗糖果。请问,他们最少需要进行多少次操作,才能使这n堆糖果满足他们的需求。

输入格式

第一行输入一个偶数n(2≤n≤200000)表示糖果的堆数。

第二行输入n个数字ai(0≤ai≤10^9)表示每一堆的糖果数。

输出格式

一个数字,表示最少需要的操作次数。

样例输入1

4
12 14 30 4

样例输出1

2

样例输入2

6
0 0 0 0 0 0

样例输出2

6

样例输入3

10
121 56 78 81 45 100 1 0 54 78

样例输出3

0

以上是题目


题解

坑点

1.“而对于每一次操作,他们只能从其中某一堆糖果当中,取出或放入一颗糖果”,这句话中相信很多人都理解为"他们只能从其中某一堆糖果当中,取出一颗糖果,放入另一堆"。我就在这个点上想了贼久,DP差点都写出来了

2.把完全平方数变为非完全平方数只需要1次操作,但把0变为非完全平方数需要2次操作

3.查找离n最近的完全平方数时,不要忘记这个数前后都有可能有满足要求的数,循环条件别错了

4.与第一条不一样,如果你已经把一堆糖果从完全平方数变非完全平方数,那完全平方数的总糖果堆数就会少1,而非完全平方数的总糖果堆数就会多1

5.求离n最近的完全平方数与n的差时别忘了加绝对值

6.语句后要打分号,scanf要打取址符,printf不打取址符…

思路

要想操作尽量少,肯定无论是完全平方数变非完全平方数,还是非完全平方数变完全平方数都要操作少:

完全平方数变非完全平方数:坑点2已经写了,所以肯定是优先选择非0完全平方数;

非完全平方数变完全平方数:对于每一个非完全平方数,先找到离他最近的完全平方数,求出差,再在这些差中选最小的来操作

实现步骤

1.先分别统计非0完全平方数、非完全平方数、0的个数,并对于每一个非完全平方数,先找到离他最近的完全平方数,求出差,保存到dif数组

2.判断

a.若完全平方数总个数等于n/2,不用任何操作,输出0即可

b.若完全平方数总个数大于n/2,优先操作非0完全平方数,再操作0,输出:非0完全平方数操作次数+0操作次数(总操作次数=完全平方数总个数-n/2)

c.若完全平方数总个数小于n/2,对dif数组进行从小到大排序,然后依次取数累加,输出答案即可(总操作次数=n/2-完全平方数总个数)

3.愉快结束程序~

关键代码讲解

1.如何快速判断一个数是否为完全平方数?

bool Check_Sqrt(int n){ //判断是否为完全平方数 
	if(sqrt(n)==(int)sqrt(n)){
		return true;
	}
	else{
		return false;
	}
	return 0;
}

c++良心的为我们提供了开平方函数,并且精度还有保证,我们知道一个对完全平方数开方得到的是一个整数,所以我们只需判断sqrt(n)是否为整数即可,而判断一个是否为整数的方法想必大家都知道,我就不多说了。

2.如何求离n最近的完全平方数?

int Dif_Sqrt(int n){ //求离n最近的完全平方数 
	for(int i=1;i<=Sqrt_10e9;i++){
		int a1=(i-1)*(i-1),a2=i*i;
		if(a1<n && a2>n){
			return (n-a1)<(a2-n)?a1:a2; 
		}
	}
} 

要求离n最近的完全平方数,主要就是求到n处于哪两个平方数之间,用循环暴力枚举,直到找到第一个大于n的完全平方数即可。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN=200000,Sqrt_10e9=31623;
int arr[MAXN+5];
bool Check_Sqrt(int n){ //判断是否为平方数 
	if(sqrt(n)==(int)sqrt(n)){
		return true;
	}
	else{
		return false;
	}
	return 0;
}
int Dif_Sqrt(int n){ //求离n最近的完全平方数 
	for(int i=1;i<=Sqrt_10e9;i++){
		int a1=(i-1)*(i-1),a2=i*i;
		if(a1<n && a2>n){
			return (n-a1)<(a2-n)?a1:a2; 
		}
	}
} 
int dif[MAXN+5];
int main(){
	int n;
	scanf("%d",&n); 
	for(int i=1;i<=n;i++){
		scanf("%d",&arr[i]);
	}
	int yes=0,no=0,ze=0; //yes表示是完全平方数的个数 ,no表示不是完全平方数的个数,ze表示0的个数 
	for(int i=1;i<=n;i++){
		if(arr[i]==0){
			ze++;
		} 
		else if(Check_Sqrt(arr[i])){
			yes++;
		}
		else{
			no++;
			dif[no]=abs(Dif_Sqrt(arr[i])-arr[i]);
		}
	}
	if((yes+ze)==n/2){
		printf("0");
		return 0;
	}
	sort(dif+1,dif+no+1);
	if((yes+ze)>n/2){
		int bia=(yes+ze)-(n/2); //需要把bia个完全平方数变为非平方数 
		if(bia<=yes){ //优先选择非0的完全平方数 
			printf("%d",bia);
		} 
		else{
			printf("%d",bia+(bia-yes));
		}
	}
	else{
		int bia=no-(n/2); //需要把bia个非平方数变为完全平方数 
		int ans=0;
		for(int i=1;i<=bia;i++){
			ans+=dif[i]; //优先选择好变的 
		} 
		printf("%d",ans); 
	} 
return 0;
}

猜你喜欢

转载自blog.csdn.net/tanfuwen_/article/details/106819437