题目链接
题目大意:
推荐看原文(特别是第一段)
给出一个 (n) 个数序列 (a) ,将(gcd(ai, ai + 1, ..., aj)) ,其中(1 le i le j le n),放入集合(S)。现在给出(m)个数的集合(S),求(a)数组。
(nle 4000 ,mle 1000)
题目思路:
非常有趣的思维体操构造题。
显然构造出来的序列不能出现给出序列以外的数,但是由于要求构造的数列可以是 (4) 倍于原序列,我们可以重复至多 (4) 次该序列的数。
现在直接给出一个构造方法:在原序列每个数后插入第一个数。即s[1] s[2] s[1] s[3] s[1]...s[m]
证明其正确性:
首先,要构造出该序列,原序列必须满足对于 (1le 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
";
return 0;
}
}
cout<<2*n-1<<endl;
cout<<a[1]<<" ";
for (int i=2;i<=n;i++) cout<<a[i]<<" "<<a[1]<<" ";
return 0;
}