【题解】数糖果

题目

题目描述

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最近的完全平方数?

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值