1. 题面梗概
中译中: 构造一个 1,…,n 的排列 p,使得每个 i∈[2,n−1],都存在一个 j∈[i,n],满足 pi=pj⊕i。
2. 逻辑推导
这个条件 pi=pj⊕i⟺pi⊕pj=i,我们要对每个 i 找一对 (pi,pj)。
而因为只需要存在一个 j 满足条件,再注意到 i∈[2,n−1],j∈[i,n],发现我们可以令 j→n⟺pj=pn。
那么条件就变成了:对于所有的 i∈[2,n−1],都有 pi⊕pn=i⟺pi=i⊕pn。
那么问题来了,pn 取什么值好呢?显然,对于异或这种位运算,只有一位的 0 和 1 绝对是首选,在本题条件下,就是设 pn=1 了,完美符合条件。
那么对于 i∈[2,n−1],直接令 pi=i⊕1 ,最后找出没有被使用的数,放到 p1 即可。
3. 代码实现
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 32 33 34 35 36 37 38 39 40 41 42
| #include <bits/stdc++.h> using namespace std; using ll = long long;
void solve( ) { int n; cin >> n; vector< int > ans( n + 1 ); vector< bool > vis( n + 1, 0 );
ans[n] = 1; vis[1] = 1; for( int i = 2; i <= n - 1; ++ i ) { ans[i] = i ^ 1; vis[ans[i]] = 1; }
int pos = 1; while( vis[pos] ) pos ++; ans[1] = pos;
for( int i = 1; i <= n; ++ i ) { cout << ans[i] << " "; } cout << '\n'; }
int main( ) { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int _t = 1; cin >> _t; while( _t -- ) { solve( ); } return 0; }
|
4. 复盘