赞
踩
要求构造一个长度为 n n n 的序列 a a a,使得:
不难发现,所有的数字选用质数一定最优,因为这样可以保证: a i ⋅ a i + 1 = a j ⋅ a j + 1 ⇔ ( a i , a i + 1 ) = ( a j , a j + 1 ) a_i \cdot a_{i + 1} = a_j \cdot a_{j + 1} \Lrarr (a_i, a_{i + 1}) = (a_j, a_{j + 1}) ai⋅ai+1=aj⋅aj+1⇔(ai,ai+1)=(aj,aj+1)
那么我们只需要保证每一对无序对 ( a i , a i + 1 ) (a_i, a_{i + 1}) (ai,ai+1) 均不同即可。
这里可以建模成一张图:以每一个值为顶点,边表示无序对(即相邻的数),每一个点还有一个自环(表示 ( a i , a i ) (a_i, a_i) (ai,ai)这样的无序对)
那么问题就转化为了,我们要选择最少的顶点数量,使得 无向完全图 中存在一条长度至少为 n − 1 n - 1 n−1,且不经过重复边的路径。
如果图上点数已经确定,考虑如何计算最长欧拉路径的长度:
最后我们只需要二分找到边数足够的 n n n,在上面跑一个欧拉路径即可
#include<bits/stdc++.h> #define fore(i,l,r) for(int i=(int)(l);i<(int)(r);++i) #define fi first #define se second #define endl '\n' #define ull unsigned long long #define ALL(v) v.begin(), v.end() #define Debug(x, ed) std::cerr << #x << " = " << x << ed; const int INF=0x3f3f3f3f; const long long INFLL=1e18; typedef long long ll; std::vector<int> minp; std::vector<int> primes; void sieve(int n){ minp.assign(n + 5, 0); primes.clear(); fore(i, 2, n + 1){ if(!minp[i]){ minp[i] = i; primes.push_back(i); } for(auto p : primes){ if(p * i > n) break; minp[i * p] = p; if(minp[i] == p) break; } } } const int N = 2000005; std::vector<int> stk; bool vis[N]; std::vector<std::pair<int, int>> g[10005]; void dfs(int u){ for(auto [v, id] : g[u]) if(!vis[id]){ vis[id] = true; dfs(v); } stk.push_back(primes[u]); } int main(){ std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout.tie(nullptr); sieve(N); int t; std::cin >> t; while(t--){ int n; std::cin >> n; auto check = [](int x, int n) -> bool { if(x & 1) return x * (x - 1) / 2 + x >= n - 1; return x * (x - 1) / 2 - (x - 2) / 2 + x >= n - 1; }; int num = 0; int l = 1, r = 10000; while(l <= r){ int mid = l + r >> 1; if(check(mid, n)){ num = mid; r = mid - 1; } else l = mid + 1; } fore(u, 0, num) g[u].clear(); int tot = 0; fore(i, 0, num) fore(j, i, num){ if(num % 2 == 0 && (i & 1) && j == i + 1) continue; //偶数个点时,去掉一些边构造欧拉路径 g[i].push_back({j, ++tot}); g[j].push_back({i, tot}); } fore(i, 0, tot + 1) vis[i] = false; stk.clear(); dfs(0); std::reverse(ALL(stk)); fore(i, 0, n) std::cout << stk[i] << " \n"[i == n -1]; } return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。