有一个 \(gcd\) 游戏,按以下步骤进行:
- 选择一个 \(n\) 的排列 \(p_1, p_2, \cdots, p_n\) 。
- 对于每个 \(i\) ,\(d_i = gcd(p_i, p_{i \% n + 1})\)
- 排列 \(p\) 的 \(score\) 为数组 \([d_1, d_2, \cdots, d_n]\) 中不同数的个数。
给一个 \(n\) ,需要构造一个排列 \(p\) ,使得 \(score_p\) 最大。
\(key\) :若一个数组中,任意 \(g = gcd(a_i, a_j)\) 存在,则数组中 \(2 \cdot g\) 存在。
- 推论:\(n\) 的排列中任选两个数可构造的 \(gcd\) 范围为 \([1, \frac{n}{2}]\) 。
如何让相邻两个数的 \(gcd\) 取遍 \([1, \frac{n}{2}]\) 。
考虑一个贪心做法: \(x | y\) 可以满足的条件之一为 \(y \geq 2x\) 。于是枚举所有奇数 \(i\) ,然后构造出一组连续的 \(i \cdot 2^k \leq n\) 。程序结束后 \(1 \sim n\) 都会出现一次,且 \([\lfloor \frac{n}{2} \rfloor + 1, n]\) 会出现在每组的最后一位。于是 \(gcd\) 取遍 \(1, \lfloor \frac{n}{2} \rfloor\) 。
view
#include <bits/stdc++.h>
typedef long long ll;
void solve(){
int n; std::cin >> n;
std::vector<int> ans;
for (int i = 1; i <= n; i += 2) {
for (int j = i; j <= n; j *= 2) {
ans.push_back(j);
}
}
for (int i = 0; i < ans.size(); i++) std::cout << ans[i] << " \n"[i == ans.size() - 1];
}
int main() {
int _ = 1; std::cin >> _;
while (_--) {solve();}
return 0;
}
- Permutation Codeforces Another Problem Roundpermutation codeforces another problem permutation another problem 1858c 题解permutation another problem permutation codeforces problem 1909i permutation codeforces problem version educational permutation codeforces round permutation codeforces mystic round permutation codeforces round swap permutation problem version 1909f another problem range query