CFS round #618(Div 2)解题报告(A,B,C)

作为一名大一的新生参加这种比赛压力真的大啊,(第一次接触计算机语言),提交人数的那个数字无时无刻都在提醒我现在是废物!!,大佬太多了,革命还得努力啊!
所以,我将我自己昨晚比赛的心得写一下:
对于A题,难度还是不大的,题目贴上:
A. Non-zero
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output

Guy-Manuel and Thomas have an array a of n integers [a1,a2,…,an]. In one step they can add 1 to any element of the array. Formally, in one step they can choose any integer index i (1≤i≤n) and do ai:=ai+1.

If either the sum or the product of all elements in the array is equal to zero, Guy-Manuel and Thomas do not mind to do this operation one more time.

What is the minimum number of steps they need to do to make both the sum and the product of all elements in the array different from zero? Formally, find the minimum number of steps to make a1+a2+ … +an≠0 and a1⋅a2⋅ … ⋅an≠0.

Input
Each test contains multiple test cases.

The first line contains the number of test cases t (1≤t≤103). The description of the test cases follows.

The first line of each test case contains an integer n (1≤n≤100) — the size of the array.

The second line of each test case contains n integers a1,a2,…,an (−100≤ai≤100) — elements of the array .

Output
For each test case, output the minimum number of steps required to make both sum and product of all elements in the array different from zero.

Example
input
4
3
2 -1 -1
4
-1 0 0 1
2
-1 2
3
0 -2 1
output
1
2
0
2
Note
In the first test case, the sum is 0. If we add 1 to the first element, the array will be [3,−1,−1], the sum will be equal to 1 and the product will be equal to 3.

In the second test case, both product and sum are 0. If we add 1 to the second and the third element, the array will be [−1,1,1,1], the sum will be equal to 2 and the product will be equal to −1. It can be shown that fewer steps can’t be enough.

In the third test case, both sum and product are non-zero, we don’t need to do anything.

In the fourth test case, after adding 1 twice to the first element the array will be [2,−2,1], the sum will be 1 and the product will be −4.
题目大意: 给你一个数组,你可以对数组里的任何元素值进行任意次数的+1(也可以是不变化)变化,使变化后的数组所有元素之和与元素之积都不为0.
而题目要求是求最少变化多少次可以达到目的!!!

思路分析: 1. 将数组里面元素为0的个数 c 进行统计且将所有元素加起来为 sum(分类讨论)

c = 0,sum!=0 直接输出 答案0,(不需要变化任何元素);
c=0,sum=0 任意改动一个元素就会使 sum>0 了,答案为1.
c>0,sum>=0 将所有的0变成1就是次数最少的了,sum一定会不会是0 ,此时答案是元素中0的个数,也就是 c
c>0,sum<0 这是最麻烦的情况了,我们分两步去分析,
第一步:将数组中为的0的元素全部变化一次,也就是变化了c次,再定义一个 sum1=0,将新的数组元素全部加起来得出了sum1,此时再对sum1进行判断,如果sum1仍然是0,那就回到了第二步(因为此时元素值为0的没有了),这种情况总共改变的最小次数是c+1 ;如果sum1>0或者sum1<0. 那最小次数就是改变了c次;

#include<bits/stdc++.h>
const int  N =  2e5+10;
using namespace std;
int a[N];

int main()
{
	std::ios::sync_with_stdio(false);
	long long int i,n,sum,m,t,k=0;
	cin>>t;
	while(t--)
	{
		cin>>n;
		sum=0;
		long long int k=0,s=0;
		for(i=1;i<=n;i++)
		{
			cin>>a[i];
			sum+=a[i];
			if(a[i]==0) s++;
		}
		if(sum!=0&&s==0) cout<<"0"<<endl;
		else
		{
			if(sum==0&&s==0)
				k=1;
			else if(sum>0&&s>0)
				k=s;
			else if(sum<0&&s>0||sum==0&&s>0)
			{sum=0;s=0; 
				for(i=1;i<=n;i++)
				{
					if(a[i]==0){a[i]=1;s++;} 
					sum+=a[i];
				}
				if(sum!=0) k=s;
				if(sum==0) k=s+1; 
			}
			cout<<k<<endl;
		}
 	}
	return 0;
}

B题倒也是纯正考math思维的题目,题目贴上
B. Assigning to Classes
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Reminder: the median of the array [a1,a2,…,a2k+1] of odd number of elements is defined as follows: let [b1,b2,…,b2k+1] be the elements of the array in the sorted order. Then median of this array is equal to bk+1.
There are 2n students, the i-th student has skill level ai. It’s not guaranteed that all skill levels are distinct.
Let’s define skill level of a class as the median of skill levels of students of the class.
As a principal of the school, you would like to assign each student to one of the 2 classes such that each class has odd number of students (not divisible by 2). The number of students in the classes may be equal or different, by your choice. Every student has to be assigned to exactly one class. Among such partitions, you want to choose one in which the absolute difference between skill levels of the classes is minimized.
What is the minimum possible absolute difference you can achieve?
Input
Each test contains multiple test cases. The first line contains the number of test cases t (1≤t≤104). The description of the test cases follows.
The first line of each test case contains a single integer n (1≤n≤105) — the number of students halved.
The second line of each test case contains 2n integers a1,a2,…,a2n (1≤ai≤109) — skill levels of students.
It is guaranteed that the sum of n over all test cases does not exceed 105.
Output
For each test case, output a single integer, the minimum possible absolute difference between skill levels of two classes of odd sizes.

Example
input
3
1
1 1
3
6 5 4 1 2 3
5
13 4 20 13 2 5 8 3 17 16
output
0
1
5
Note
In the first test, there is only one way to partition students — one in each class. The absolute difference of the skill levels will be |1−1|=0.
In the second test, one of the possible partitions is to make the first class of students with skill levels [6,4,2], so that the skill level of the first class will be 4, and second with [5,1,3], so that the skill level of the second class will be 3. Absolute difference will be |4−3|=1.
Note that you can’t assign like [2,3], [6,5,4,1] or [], [6,5,4,1,2,3] because classes have even number of students.
[2], [1,3,4] is also not possible because students with skills 5 and 6 aren’t assigned to a class.
In the third test you can assign the students in the following way: [3,4,13,13,20],[2,5,8,16,17] or [3,8,17],[2,4,5,13,13,16,20]. Both divisions give minimal possible absolute difference.
题目大意: 给你一个数n,下面列出2n个元素的数组,然后将这2n个数分成两组,每组元素个数都是奇数个,两组元素个数可以不相等,所有元素都要被分配而且只能分到一个数组里,然后问你怎么分配使这两个数组的中位数存在最小绝对值差。
思路分析: 我认为没什么可以分析的,就是初高中那时的知识点:将2n数组进行排序,下标编号是0~n-1,则两个数组最小中位数差的绝对值最小就是下标为n-1的元素减下标为n的元素的绝对值就是答案。

#include<bits/stdc++.h>
const int  N =  2e5+10;
using namespace std;
long long int a[N];
 
int main()
{
	std::ios::sync_with_stdio(false);
	long long int i,n,sum,t;
	cin>>t;
	while(t--)
	{
		cin>>n;
		sum=0;
		for(i=0;i<n*2;i++)
			cin>>a[i];
		sort(a+0,a+n*2);
		sum=fabs(a[n-1]-a[n]);
		cout<<sum<<endl;	
 	}
	return 0;
}

C题我想了有那么久了,第一眼看懂题意的时候我就懵逼了,什么玩意啊,又是考数学的思维,不过加上了位运算的知识点 题目贴上:
C. Anu Has a Function
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
Anu has created her own function f: f(x,y)=(x|y)−y where | denotes the bitwise OR operation. For example, f(11,6)=(11|6)−6=15−6=9. It can be proved that for any nonnegative numbers x and y value of f(x,y) is also nonnegative.

She would like to research more about this function and has created multiple problems for herself. But she isn’t able to solve all of them and needs your help. Here is one of these problems.

A value of an array [a1,a2,…,an] is defined as f(f(…f(f(a1,a2),a3),…an−1),an) (see notes). You are given an array with not necessarily distinct elements. How should you reorder its elements so that the value of the array is maximal possible?

Input
The first line contains a single integer n (1≤n≤105).

The second line contains n integers a1,a2,…,an (0≤ai≤109). Elements of the array are not guaranteed to be different.

Output
Output n integers, the reordering of the array with maximum value. If there are multiple answers, print any.

Examples
inputCopy
4
4 0 11 6
outputCopy
11 6 4 0
inputCopy
1
13
outputCopy
13
Note
In the first testcase, value of the array [11,6,4,0] is f(f(f(11,6),4),0)=f(f(9,4),0)=f(9,0)=9.

[11,4,0,6] is also a valid answer.
有对位运算知识点欠缺的老铁们可以看看这位博主的文章Marccco挺详细的
这道题现在回想起来也不难,
题目的意思大概是讲: 给你一个数组,按照题目要求的算法函数f求出最大元素值,循环 f(f(…f(f(a1,a2),a3),…an−1),an) 直到算出最后一位元素值,现在你的目的是求出怎么排序原数组可以使这样求出的最后一位元素值最大。
思路分析: 我们知道一个数(这里讨论正整数)都是以32位的二进制来表示的,比如11就是00000000000000000000000000001011 验证一下:从右边开始算:1 *2^0 + 1 * 2^1 + 0 * 2 ^ 2 + 1 * 2^ 3 = 1 + 2 +0 +8 =11(前面的好多0都可以不用算了),这道题目就是尽可能将高位(靠左边的)的0变成1,我们知道按位或 “|” 运算符就是取两者的最大并集,如0|0=0;1|0=1;1|1=1;
我们可以开辟一个数组来存储32位上每位出现1的次数,然后从最高位开始遍历,如果这个位的1只有一次,我们把它调到最前面来运算,因为这样子我们可以最大上补齐32位码上空缺的1使新的元素尽可能最大,至于后面的数,顺便排序,因为他们位上有1已经对能等到最大元素值没有什么帮助了!

#include<bits/stdc++.h>
typedef unsigned long long int ll;
#define IOS std::ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
const int size = 2e5+6;
using namespace std;
ll ans[55],a[size],book[size];

//这道题就是尽量将二进制中1的位数最高的数往前面放 
//所以说找到第一个数才是本题最关键的一步 

int main(void)
{
	int n,i,j;
	cin>>n;
	for(i=1;i<=n;i++)
	{
		cin>>a[i];
		book[i]=1;//每个数的位置打上一个标记 
		for(j=0;j<=31;j++)
		{
			if((a[i] >> j)&1==1)
				ans[j]++;
		}
	} 
	//从最高位开始遍历 
	for(i=31;i>=0;i--)
	{
		if(ans[i]-1==0)  //找到第一个某个位数为1的只有一个时保存,
						 //找到它编号并提到最前面 
		{
			for(j=1;j<=n;j++)
			{
				if((a[j] >> i)&1==1)
				{
					book[j]=2;
					cout<<a[j]<<' ';
					break;
				}		
			}
			for(j=1;j<=n;j++)
				if(book[j]==1)
					cout<<a[j]<<' ';
			return 0;
		}
	}
	//特殊情况,如果所有的数位上都是0,随便输出
	for(j=1;j<=n;j++) cout<<a[j]<<' ';
	cout<<endl;
	return 0; 
}

D,E两题考试没做出来,待补,希望这篇博客对大家有帮助,有问题留言,谢谢

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凌晨小街

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值