• CodeForces 894C Marco and GCD Sequence|构造


    题目链接
    题目大意:

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

    给出一个 (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;
    }
    
  • 相关阅读:
    旧题复习{6}
    CF219D. Choosing Capital for Treeland [树形DP]
    POJ1947 Rebuilding Roads[树形背包]

    洛谷P1280 尼克的任务[DP]
    NOIP2003pj栈[卡特兰数]
    NOIP2001统计单词个数[序列DP]
    洛谷P1415 拆分数列[序列DP 状态 打印]
    POJ2828 Buy Tickets[树状数组第k小值 倒序]
    CF380C. Sereja and Brackets[线段树 区间合并]
  • 原文地址:https://www.cnblogs.com/fmj123/p/14253343.html
Copyright © 2020-2023  润新知