GCD构造排列

题目

给定一个长度为n的数组a,试复原长度为n的排列p
其中ai=gcd(p1,p2,...,pi),也就是说,ai表示排列p中前i个数字的最大公约数。
(由于数组a可能是错误的,故有可能无解,此时输出1即可)
https://ac.nowcoder.com/acm/problem/269091

Input

输入包括两行
第一行一个正整数n(1n2×105)表示数组a的长度。
第二行n个正整数ai(1ain)表示数组a中的元素。

4
4 2 1 1

Output

输出一行包含n个整数,表示符合条件的排列p,如果有多解则输出任意一个。
无解则输出1

4 2 1 3

说明
a1=gcd(p1)=4
a2=gcd(p1,p2)=2
a3=gcd(p1,p2,p3)=1
a4=gcd(p1,p2,p3,p4)=1

题解

解题思路

首先,判断a数组的正确性,根据最大公约数的定义,随着i的递增,ai的值应该逐渐变小,且第i个数应该是第i1个数的因数,即(i1)modi==0

随后开始构造,由于是排列,因此需要设立一个vis数组判断当前的数没有被填过,对于每一个位置,观察到相邻两个位置之间如果可以填最大公约数非1的数时,此时a数组相邻的两个数不相等。

如果a数组中相邻两个数相等时,则p排列中这两个数互质,即可以通过从较小的数加上ai获得更大的数字填入排列。

如果完成上述步骤后仍然无法填上任何数字,则证明数组a是错误的,输出1

Code

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long LL;

int gcd(int a,int b){return b==0?a:gcd(b,a%b);}

void solve(){
	int n;cin>>n;
    vector<int> a(n+1);
    
    for(int i=1;i<=n;i++){
        cin>>a[i];
        if(i>=2 and a[i-1]%a[i]!=0){
            cout<<"-1"<<endl;
            return;
        }
    }
    vector<int> ans(n+1);
    vector<bool> vis(n+1);
    for(int i=1;i<=n;i++){
        if(a[i]!=a[i-1]){
            ans[i]=a[i];
        }
        else{
            for(int j=ans[i-1]+a[i];j<=n;j+=a[i]){
                if(!vis[j] and gcd(a[i-1],j)==a[i]){
                    ans[i]=j;
                    break;
                }
            }
            if(!ans[i]){
                cout<<"-1"<<endl;
                return;
            }
        }
        vis[ans[i]]=1;
    }
    for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
}
signed main(){
	ios::sync_with_stdio(false); cin.tie(nullptr);
	int t=1;
	//cin>>t;
	while(t--) solve();
	return 0;
}

posted on   TaopiTTT  阅读(16)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示