CF round#669 div2 A题

A. Ahahahahahahahaha

题目链接

  • time limit per test: 1 second

  • memory limit per test: 256 megabytes

  • input: standard input

  • output: standard output

Alexandra has an even-length array a a a, consisting of 0 0 0s and 1 1 1s. The elements of the array are enumerated from 1 1 1 to n n n. She wants to remove at most n 2 \frac{n}{2} 2n elements (where n n n — length of array) in the way that alternating sum of the array will be equal 0 0 0 (i.e. a 1 − a 2 + a 3 − a 4 + . . . = 0 a_1-a_2+a_3-a_4+...=0 a1a2+a3a4+...=0). In other words, Alexandra wants sum of all elements at the odd positions and sum of all elements at the even positions to become equal. The elements that you remove don’t have to be consecutive.

For example, if she has a = [ 1 , 0 , 1 , 0 , 0 , 0 ] a=[1, 0, 1, 0, 0, 0] a=[1,0,1,0,0,0] and she removes 2 2 2nd and 4 4 4th elements, aa will become equal [ 1 , 1 , 0 , 0 ] [1, 1, 0, 0] [1,1,0,0] and its alternating sum is 1 − 1 + 0 − 0 = 0 1-1+0-0=0 11+00=0.

Help her!

Input

Each test contains multiple test cases. The first line contains the number of test cases t ( 1 ≤ t ≤ 1 0 3 ) t(1\leq t\leq 10^3) t(1t103). Description of the test cases follows.

The first line of each test case contains a single integer n ( 2 ≤ n ≤ 1 0 3 , n n(2\leq n\leq10^3, n n(2n103,n is even ) ) ) — length of the array.

The second line contains n n n integers a 1 , a 2 , . . . , a n ( 0 ≤ a i ≤ 1 ) a_1, a_2, ..., a_n(0\leq a_i\leq 1) a1,a2,...,an(0ai1) — elements of the array.

It is guaranteed that the sum of n n n over all test cases does not exceed 1 0 3 10^3 103.

Output

For each test case, firstly, print k ( n 2 ≤ k ≤ n ) k(\frac n2 \leq k \leq n) k(2nkn) — number of elements that will remain after removing in the order they appear in a a a. Then, print this k k k numbers. Note that you should print the numbers themselves, not their indices.

We can show that an answer always exists. If there are several answers, you can output any of them.

Example
input
4
2
1 0
2
0 0
4
0 1 1 1
4
1 1 0 0
output
1
0
1
0
2
1 1
4
1 1 0 0
Note

In the first and second cases, alternating sum of the array, obviously, equals 0 0 0.

In the third case, alternating sum of the array equals 1 − 1 = 0 1-1=0 11=0.

In the fourth case, alternating sum already equals 1 − 1 + 0 − 0 = 0 1-1+0-0=0 11+00=0, so we don’t have to remove anything.


题目大意:

有一个长度为 n n n( n n n是偶数)的,仅由0和1构成的数组

从中删去至多 n 2 \frac n2 2n个元素,使得在奇数位置和偶数位置的和相等,即 a 1 − a 2 + a 3 − a 4 + . . . = 0 a_1-a_2+a_3-a_4+...=0 a1a2+a3a4+...=0

方法1

如果奇数位置和偶数位置的数全都相同,即删除后的数组为全0或者全1(偶数个),那么奇数和肯定等于偶数和

先数一下数组里有多少个0和多少个1

  • 如果0比1多,那么先把数组中的1全部删去,此时删除次数肯定不超过n/2,得到的全0数组满足条件
  • 如果1比0多,那么先把数组中的0全部删去,此时删除次数肯定不超过n/2,如果剩余的元素个数为奇数,那么再删除一个1,如果为偶数则不删除
  • 如果1的数量和0的数量相等,那么把数组中所有的1删去,此时删除次数恰好等于n/2,满足条件

这个是最简单的方法了,只需要数1和0的个数,然后输出对应个数的1或0即可

方法2

考虑连续的2个单元,只有可能出现4种情况

  • 0 0和1 1这两种情况对奇数和偶数的贡献都是一样的,所以奇数偶数的和不由他们所改变
  • 0 1和1 0这两种情况对奇数或偶数贡献了一个1,如果要使其贡献变为0,只需要删除其中的1就可以了
  • 需要注意的是,就算删除了前面的0 1中的1,导致了后面的元素前移,但是移动后的0 0和1 1对奇偶的贡献仍然相同,移动后的0 1和1 0虽然相对于移动前改变了,但处理这两种情况的策略仍然是将1删除,处理后的效果仍然不变
  • 每次操作至多删除2个元素中的1个,可以保证操作次数小于等于n/2
究极复杂的方法

我比赛的时候脑抽死活想不出简单的方法,只能简单问题复杂化。结论是只需要做一次删除操作即可满足题意。

前两种方法的代码都极其容易写,所以我就不写了,只放一个我的复杂代码出来丢人

简单问题怎么复杂化呢?直接求n个元素的和sum,由于这n个元素全部都是由0和1构成的,那么每加一个元素,和的变动最多只能为1,也就是说一定存在某一个位置idx,使得[0, idx]这个子区间的和为(sum+1)/2,而[idx+1, n]这个子区间的和为sum-(sum+1)/2

已知增删一个元素可以让这个元素之后的原来奇数位置的元素变为偶数位置,偶数位置的元素变为奇数位置,这个变化过程中所有元素的权重会变为原来的相反数,那么原来这个元素之后的所有元素之和也会变成原来的相反数,只需要在idx附近删除1个或者2个元素就可以使前idx个元素的和与idx之后所有元素的和相等,并且考虑加权的情况下互为相反数,从而满足题目条件

实际上只需要删除1个元素就可以做到,借用上一种情况的讨论,0 0和1 1这两种情况不论怎么移动都是不会对最终结果造成影响的,所以可以直接删去,不断删去这两种序列直到数组中没有这样的序列之后,数组一定是一个0 1 0 1 … 0 1或者是1 0 1 0 … 1 0这样的数组,对于第一种情况,如果0 1出现偶数次,那么只要删除最中间的那个0就可以了;如果0 1出现奇数次,那么只要删除最中间的那个1就可以了。第二种情况类似。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 5;
int a[maxn], b[maxn], c[maxn];
int main() {
	int T; scanf("%d", &T);
	while(T--) {
		int n; scanf("%d", &n);
		for(int i = 0; i < n; ++i)
			scanf("%d", &a[i]);
		int cnt = -1;
		for(int i = 0; i < n; ++i) {
			if(cnt == -1 || b[cnt] != a[i]) {
				++cnt;
				b[cnt] = a[i]; c[cnt] = i;
			}
			else --cnt;
		}
		if(cnt == -1) {
			printf("%d\n", n);
			for(int i = 0; i < n; ++i)
				printf("%d%c", a[i], " \n"[i == n-1]);
		}
		else {
			if(cnt % 2 == 0)
				a[c[cnt/2]] = -1;
			else {
				if((cnt+1) % 4 == 0) {
					if(b[cnt/2] == 0)
						a[c[cnt/2]] = -1;
					else
						a[c[cnt/2 + 1]] = -1;
				}
				else {
					if(b[cnt/2] == 1)
						a[c[cnt/2]] = -1;
					else
						a[c[cnt/2 + 1]] = -1;
				}
			}
			printf("%d\n", n-1);
			for(int i = 0; i < n; ++i) {
				if(a[i] == -1) continue;
				printf("%d", a[i]);
				if(i < n-1) printf(" ");
			}
			printf("\n");
		}
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值