CodeForces 894C Marco and GCD Sequence|构造

题目链接
题目大意:

推荐看原文(特别是第一段)

给出一个 \(n\) 个数序列 \(a\) ,将\(gcd(ai, ai + 1, ..., aj)\) ,其中\(1 \le i \le j \le n\),放入集合\(S\)。现在给出\(m\)个数的集合\(S\),求\(a\)数组。

\(n\le 4000 ,m\le 1000\)

题目思路:

非常有趣的思维体操构造题。

显然构造出来的序列不能出现给出序列以外的数,但是由于要求构造的数列可以是 \(4\) 倍于原序列,我们可以重复至多 \(4\) 次该序列的数。

现在直接给出一个构造方法:在原序列每个数后插入第一个数。即s[1] s[2] s[1] s[3] s[1]...s[m]

证明其正确性:

首先,要构造出该序列,原序列必须满足对于 \(1\le i \le m\)\(s_i\)\(s_1\) 倍数

因为 \(s_1\) 一定是整个序列的GCD,否则 \(s_1\) 必定无法是序列中任何一段的GCD。

那么,整个序列必定\(s_1\) 的倍数。若存在一个 \(s_i\) 不是 \(s_1\) 的倍数,则若存在这个序列,其中一段的GCD不是 \(s_1\) 的倍数,根据GCD的性质,这一段数向左,向右伸展,其GCD也必然不是 \(s_1\) 的倍数,那么整个序列的GCD一定不是 \(s_1\)。与上面矛盾,不成立。若出现这种情况,输出 -1 即可。

根据此性质,按照我们的构造方法,单一一个数的GCD是其本身,多个数由于 \(s_1\) 的存在,其GCD必定为 \(s_1\),符合题意。

上代码

#include<bits/stdc++.h>
using namespace std;
int n,a[1500];
int gcd(int x,int y)
{
	if (!y) return x;
	return gcd(y,x%y);
}
int main()
{
	cin>>n;
	for (int i=1;i<=n;i++)
	{
		cin>>a[i];
		if (gcd(a[i],a[1])!=a[1]) 
		{
			cout<<"-1\n";
			return 0;
		}
	}
	cout<<2*n-1<<endl;
	cout<<a[1]<<" ";
	for (int i=2;i<=n;i++) cout<<a[i]<<" "<<a[1]<<" ";
	return 0;
}
posted @ 2021-01-08 20:47  fmj_123  阅读(74)  评论(0编辑  收藏  举报