文章目录
- 题目描述
- 输入格式
- 输出格式
- 样例输入1
- 样例输出1
- 提交链接
- 提示
- 解析
- 参考代码
题目描述
格格有一个长度为 n n n 的排列 p p p,但她不记得 p p p 具体的样子,她只记得数组 a a a。
其中: a i = g c d ( p 1 , p 2 , . . . , p i ) a_i=gcd(p_1,p_2,...,p_i) ai=gcd(p1,p2,...,pi),也就是说, a i a_i ai 表示排列 p p p 中前 i i i 个数字的最大公约数。
现在,她希望小苯将排列 p p p 复原出来,请你帮帮他吧。
(但有可能无解,这意味着格格给出的 a a a 数组可能是不正确的,此时输出 − 1 −1 −1 即可。)
输入格式
输入包含两行。
第一行一个正整数 n ( 1 ≤ n ≤ 2 × 1 0 5 ) n (1≤n≤2×10^5) n(1≤n≤2×105),表示数组 a a a 的长度。
第二行 n n n 个正整数 a i ( 1 ≤ a i ≤ n ) a_i (1≤a_i≤n) ai(1≤ai≤n),表示数组 a a a 的元素。
输出格式
输出包含一行 n n n 个正整数,表示符合条件的排列 p p p。
如果有多个解,输出任意方案即可。
如果无解,请输出一个数字: − 1 −1 −1。
样例输入1
4
4 2 1 1
样例输出1
4 2 1 3
提交链接
https://ac.nowcoder.com/acm/contest/82957/D
提示
排列:长度为 n n n 的排列是一个数组,满足其中 1 1 1 到 n n n 的每个正整数恰好出现一次。
样例解释:
首先输出是一个排列,且满足格格的要求:
a 1 = g c d ( p 1 ) = 4 a_1=gcd(p_1)=4 a1=gcd(p1)=4
a 2 = g c d ( p 1 , p 2 ) = 2 a_2=gcd(p_1,p_2)=2 a2=gcd(p1,p2)=2
a 3 = g c d ( p 1 , p 2 , p 3 ) = 1 a_3=gcd(p_1,p_2,p_3)=1 a3=gcd(p1,p2,p3)=1
a 4 = g c d ( p 1 , p 2 , p 3 , p 4 ) = 1 a_4=gcd(p_1,p_2,p_3,p_4)=1 a4=gcd(p1,p2,p3,p4)=1
解析
根据 a [ i ] = g c d ( p [ 1 ] , . . . , p [ i ] ) a[i]=gcd(p[1],...,p[i]) a[i]=gcd(p[1],...,p[i])、 a [ i − 1 ] = g c d ( p [ 1 ] , . . . , p [ i − 1 ] ) a[i-1]=gcd(p[1],...,p[i-1]) a[i−1]=gcd(p[1],...,p[i−1]),即 a [ i ] = g c d ( a [ i − 1 ] , p [ i ] ) a[i]=gcd(a[i-1],p[i]) a[i]=gcd(a[i−1],p[i])。
可以得到 a [ i − 1 ] % a [ i ] = 0 a[i-1]\%a[i]=0 a[i−1]%a[i]=0
即, a a a 数组递减的,且满足 a [ i − 1 ] % a [ i ] = 0 a[i-1]\%a[i]=0 a[i−1]%a[i]=0 或 a [ i − 1 ] = a [ i ] a[i-1]=a[i] a[i−1]=a[i]
确定 a n s ans ans 数组,分为两种情况。
-
a [ i − 1 ] > a [ i ] a[i-1]>a[i] a[i−1]>a[i]
a n s ans ans 数组的第 i i i 个位置填 a [ i ] a[i] a[i]。证明:
a [ i − 1 ] = g c d ( a n s [ 1 ] , . . . , a n s [ i − 1 ] ) > a [ i ] = g c d ( a n s [ 1 ] , . . . , a n s [ i ] ) a[i-1]=gcd(ans[1],...,ans[i-1])>a[i]=gcd(ans[1],...,ans[i]) a[i−1]=gcd(ans[1],...,ans[i−1])>a[i]=gcd(ans[1],...,ans[i]) = > => =>
m i n ( a n s [ 1 ] , . . , a n s [ i − 1 ] ) > m i n ( a n s [ 1 ] , . . . , a n s [ 1 ] ) min(ans[1],..,ans[i-1])>min(ans[1],...,ans[1]) min(ans[1],..,ans[i−1])>min(ans[1],...,ans[1]) = > => =>
a n s [ 1 ] ∼ a n s [ i − 1 ] ans[1] \sim ans[i-1] ans[1]∼ans[i−1] 与 a n s [ i ] ans[i] ans[i] 不相等, a [ i ] a[i] a[i] 未使用。又要保证 a n s [ 1 ] ∼ a n s [ i ] ans[1] \sim ans[i] ans[1]∼ans[i] 的最大公约数为 a [ i ] a[i] a[i],则 a n s [ i ] = a [ i ] ans[i]=a[i] ans[i]=a[i] -
a [ i − 1 ] = a [ i ] a[i-1]=a[i] a[i−1]=a[i]
a n s [ i ] ans[i] ans[i] 数组的第 i i i 个位置填 a [ i ] a[i] a[i] 未使用的倍数。
a [ i ] = g c d ( a n s [ 1 ] , . . , a n s [ i ] ) a[i]=gcd(ans[1],..,ans[i]) a[i]=gcd(ans[1],..,ans[i]),可以得到 a n s [ i ] ans[i] ans[i] 为 a [ i ] a[i] a[i] 的倍数, a n s [ i − 1 ] ans[i-1] ans[i−1] 为 a [ i ] a[i] a[i] 的倍数。
我们可以这样构造: a [ i ] a[i] a[i] 的倍数从小到大使用。即当填 a n s ans ans 数组的第 i i i 个位置时,小于等于 a n s [ i − 1 ] ans[i-1] ans[i−1] 的 a [ i ] a[i] a[i] 的倍数都已经被使用。
我们可以从 a n s [ i − 1 ] + a [ i ] ans[i-1]+a[i] ans[i−1]+a[i] 开始找 a [ i ] a[i] a[i] 的倍数,大大减少时间复杂度。
参考代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 9;
int n, a[maxn], ans[maxn];
bool vis[maxn];
int main()
{cin >> n;for (int i = 1; i <= n; i++)cin >> a[i];bool book = false;for (int i = 1; i <= n; i++){if (i >= 2 && a[i - 1] % a[i] != 0) //a数组必须满足 a[i-1] % a[i] = 0{book = true;break;}}if (!book){for (int i = 1; i <= n; i++){if (a[i - 1] != a[i])ans[i] = a[i];else{for (int k = ans[i - 1] + a[i]; k <= n; k += a[i]) // 找a[i]的倍数{if (!vis[k]){ans[i] = k;break;}}}if (!ans[i]){book = true;break;}vis[ans[i]] = true;}}if (book)cout << -1;else{for (int i = 1; i <= n; i++)cout << ans[i] << " ";}return 0;
}