GCD Compression

题目大意:

有一个数组 a 其中有 2n 个数,把它压缩进数组 b,b 的大小是 n-1。
所谓的“压缩”指的是两种操作:

  • 首先舍弃 a 当中的两个数(你可以任意选择)。
  • 然后每次取出剩下的数组 a 当中的两个数,把他们的和放入数组 b 当中。

要求最终 b 数组中所有数的最大公约数(gcd)要大于 1,即 gcd{b_1,b_2,...,b_n-1}>1
请你把你每一次从 a 中取出的两个数在原来的 a 中的下标输出,如果答案不唯一输出任意一种即可。

题解:

如题目所说,保证每一组数据都有解,那么为什么一定有解呢?

  首先,给定的序列里,数的种类可以分成奇数和偶数,对于奇数来说,每两个奇数的和是偶数,对于偶数来说,每两个偶数的和也一定是偶数。因此,我们只需要将2n-2个数取出,合并,使每个数都为偶数,即可保证最大公因数至少为二

  那么,我们应该如何取这2n-2个数呢?
  如何取数,受制于数列里奇数和偶数的个数。因为数列里的数的总数为2n为偶数,所以如果奇数的个数为奇数,那么偶数的个数也为奇数,这时候只需要奇数偶数分别扔一个出去即可保证两两之间有符合要求的匹配。如果奇数的个数为偶数,偶数的个数也为偶数,那么随便选奇数或偶数扔两个数出去即可(前提是你选中的这种数的类型(奇数or偶数)所包括的数的个数至少大于或等于二

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2005;
struct p{
	int num,pos;
	p(){}
	p(int nnum,int ppos){
		nnum = nnum;
		pos = ppos;
	}
};//记录数列中每个数的大小和下标
vector<p> j,o;//j记录奇数,o记录偶数
int t,n,a[MAXN],cntj,cnto;
int main(){
	cin >> t;
	while(t--){
		j.clear();
		o.clear();
		memset(a,0,sizeof a);
		cin >> n;
		for(int i = 1; i <=  2 * n; i++){
			cin >> a[i];
			if(a[i] % 2 == 1)j.push_back(p(a[i],i));//存数
			else o.push_back(p(a[i],i));
		}
		if(j.size() % 2 == 0 && o.size() % 2 == 0){//判两种类型的数的个数的情况并进行相应的处理
			for(int i = 2; i < j.size(); i+=2){
				cout << j[i].pos << " " << j[i + 1].pos<< "\n"; 
			}
			for(int i = 0; i < o.size(); i+=2){
				cout << o[i].pos<< " " << o[i + 1].pos << "\n"; 
			}
		}
		else if(j.size() % 2 == 1 && o.size() % 2 == 1){
			for(int i = 1; i < j.size(); i+=2){
				cout << j[i].pos << " " << j[i + 1].pos << "\n";
			}
			for(int i = 1; i <o.size(); i+=2){
				cout << o[i].pos<< " " << o[i + 1].pos<< "\n"; 
			}
		} 
	}
}
posted @ 2022-07-11 21:32  腾云今天首飞了吗  阅读(23)  评论(0编辑  收藏  举报