Codeforces Round 949
D. Turtle and Multiplication
Turtle 刚刚在数学课上学会了如何乘法两个整数,他非常兴奋。
然后 Piggy 给了他一个整数
,并让他构造一个序列 ,该序列满足以下条件:
- 对于所有
, 。 - 对于所有
, 。 在所有满足上述条件的序列中,Piggy 要求 Turtle 找到一个不同元素数量最小的序列。
Turtle 显然无法解决这个问题,所以请帮帮他!
只需要考虑所有元素都是质数的情况。这是因为,如果所有元素都是质数,那么我们只需要保证任意相邻项对应的无序二元组各不相等(这里的不相等指的是,无序二元组
假设我们已经选取了
设这些质数为
也就是点集
我们要寻找这样的路径,这个路径经过这个图的尽可能多的边,且每条边最多经过 1 次.
显然这个路径是这个图中删除一些边后形成的新的图的欧拉路径.
我们需要求最长的路径.
当
CAUTION
- 无向图中,一个自环会给一个结点带来
的度数.
当
这样,这个图中恰有 2 个奇数度点,这两个点分别为这个欧拉路径的起点和终点。我们得到了一个具有欧拉路径的图,路径的边数是
因此,对于
构造出的序列的长度,即路径的点数是
只需要求出最小的正整数
当确定
这里,我们
细节请见代码.
#include <algorithm>
#include <cassert>
#include <iostream>
#include <map>
#include <vector>
std::vector<int> Hierholzer(const std::vector<std::vector<int>> &g) {
int n = (int)g.size();
if (n == 0) {
return {};
}
std::vector<std::map<int, int>> num(n, std::map<int, int>());
for (int u = 0; u < n; ++u) {
for (int v : g[u]) {
++num[u][v];
}
}
int begin = 0;
for (int u = 1; u < n; ++u) {
if ((int)g[begin].size() == 0 && (int)g[u].size() != 0) {
begin = u;
} else if ((int)g[begin].size() % 2 != 1 &&
(int)g[u].size() % 2 == 1) {
begin = u;
}
}
std::vector<int> ans;
std::vector<int> idx(n, 0);
std::vector<int> st;
st.push_back(begin);
while (!st.empty()) {
int u = st.back();
if (idx[u] < (int)g[u].size()) {
int v = g[u][idx[u]];
if (num[u][v] > 0) {
--num[u][v];
--num[v][u];
st.push_back(v);
}
++idx[u];
} else {
ans.push_back(u);
st.pop_back();
}
}
std::reverse(ans.begin(), ans.end());
return ans;
}
bool check(const std::vector<std::vector<int>> &g,
const std::vector<int> &path) {
int n = (int)g.size();
int m = 0;
std::vector<std::map<int, int>> num(n, std::map<int, int>());
for (int u = 0; u < n; ++u) {
for (int v : g[u]) {
++num[u][v];
++m;
}
}
int ps = (int)path.size();
for (int i = 0; i + 1 < ps; ++i) {
int u = path[i];
int v = path[i + 1];
if (u < 0 || u >= n || v < 0 || v >= n || num[u][v] == 0) {
return false;
}
--num[u][v];
--m;
--num[v][u];
--m;
}
return m == 0;
}
long long calc(long long k) {
if (k % 2 == 1) {
return k * (k + 1) / 2 + 1;
} else {
return k * k / 2 + 2;
}
}
std::vector<long long> get_primes(long long x) {
std::vector<long long> res;
std::vector<long long> vis(x + 1, 0);
long long i = 2;
while (i <= x) {
if (!vis[i]) {
res.push_back(i);
for (long long j = i; j <= x; j += i) {
vis[j] = 1;
}
}
++i;
}
return res;
}
std::vector<long long> primes = get_primes(11807);
void solve() {
int n;
std::cin >> n;
int l = 1, r = n;
while (l < r) {
int m = (l + r) / 2;
if (calc(m) >= n) {
r = m;
} else {
l = m + 1;
}
}
int k = l;
std::vector<std::vector<int>> g(k, std::vector<int>());
if (k % 2 == 1) {
for (int i = 0; i < k; ++i) {
for (int j = i; j < k; ++j) {
g[i].push_back(j);
g[j].push_back(i);
}
}
} else {
for (int i = 0; i < k; ++i) {
for (int j = i; j < k; ++j) {
if (i % 2 == 1 && i >= 1 && i <= k - 3 && j == i + 1) {
continue;
}
g[i].push_back(j);
g[j].push_back(i);
}
}
}
auto v = Hierholzer(g);
// assert(check(g, v));
for (int i = 0; i < n; ++i) {
std::cout << primes[v[i]] << " \n"[i == n - 1];
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t;
std::cin >> t;
while (t--) {
solve();
}
return 0;
}