题意略。
思路:
第一问:
递归地来写,找对称,发现关于(1<<y) - 1和(1<<y)对称的数字做 & 结果为0。
第二问:
6,7特殊考虑。循环左移(1<<y) ~ (1<<(y + 1) - 1),可以保证这个区间内的值与下标做 & 结果不为0。然而如果在这个段内只有1<<y这一个数,那么
我们无法循环左移,此时要特判为NO。
详见代码:
#include<bits/stdc++.h> #define maxn 50 #define maxn2 100005 using namespace std; int one[maxn],tail; int ans1[maxn2],ans2[maxn2]; int six[] = {3,6,2,5,1,4}; int seven[] = {7,6,2,5,1,4,3}; void init(){ one[0] = 0; tail += 1; for(int i = 1;(1<<i) - 1 <= 1000000;++i){ one[i] = (1<<i) - 1; tail += 1; } } int cnt1(int x){ int ret = 0; while(x){ x = x & (x - 1); ++ret; } return ret; } void construct(int x){ if(x <= 0) return; int pos = lower_bound(one,one + tail,x) - one - 1; int mid = one[pos] + 1; for(int i = mid;i <= x;++i) swap(ans2[i],ans2[mid - (i - mid) - 1]); x = mid - (x - mid) - 1 - 1; construct(x); } int main(){ init(); int n; scanf("%d",&n); if(n & 1) printf("NO "); else{ printf("YES "); for(int i = 1;i <= n;++i) ans2[i] = i; construct(n); printf("%d",ans2[1]); for(int i = 2;i <= n;++i) printf(" %d",ans2[i]); printf(" "); } if(n <= 5 || cnt1(n) == 1) printf("NO "); else if(n == 6){ printf("YES "); printf("%d",six[0]); for(int i = 1;i < 6;++i) printf(" %d",six[i]); printf(" "); } else if(n == 7){ printf("YES "); printf("%d",seven[0]); for(int i = 1;i < 7;++i) printf(" %d",seven[i]); printf(" "); } else{ printf("YES "); for(int i = 1;i <= 7;++i) ans1[i] = seven[i - 1]; int lft = 8,rht = min((lft<<1) - 1,n); while(lft < n){ for(int i = lft;i <= rht;++i){ if(i < rht) ans1[i] = i + 1; else ans1[i] = lft; } lft = lft<<1; rht = min((lft<<1) - 1,n); } printf("%d",ans1[1]); for(int i = 2;i <= n;++i) printf(" %d",ans1[i]); printf(" "); } return 0; }