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;
}