题目描述
You have an array $ a_0, a_1, \ldots, a_{n-1} $ of length $ n $ . Initially, $ a_i = 2^i $ for all $ 0 \le i \lt n $ . Note that array $ a $ is zero-indexed.
You want to reverse this array (that is, make $ a_i $ equal to $ 2^{n-1-i} $ for all $ 0 \le i \lt n $ ). To do this, you can perform the following operation no more than $ 250,000 $ times:
- Select an integer $ i $ ( $ 0 \le i \lt n $ ) and replace $ a_i $ by $ a_i \oplus a_{(i+1)\bmod n} $ .
Here, $ \oplus $ denotes the bitwise XOR operation.
Your task is to find any sequence of operations that will result in the array $ a $ being reversed. It can be shown that under the given constraints, a solution always exists.
输入格式
The first line contains a single integer $ n $ ( $ 2 \le n \le 400 $ ) — the length of the array $ a $ .
输出格式
On the first line print one integer $ k $ ( $ 0 \le k \le 250,000 $ ) — the number of operations performed.
On the second line print $ k $ integers $ i_1,i_2,\ldots,i_k $ ( $ 0 \le i_j \lt n $ ). Here, $ i_j $ should be the integer selected on the $ j $ -th operation.
Note that you don't need to minimize the number of operations.
样例 #1
样例输入 #1
2
样例输出 #1
3
1 0 1
样例 #2
样例输入 #2
3
样例输出 #2
9
1 0 1 0 2 1 0 1 0
提示
In the notes, the elements on which the operations are performed are colored red.
In the first test case, array $ a $ will change in the following way:
$ [1,\color{red}{2}] \rightarrow [\color{red}{1},3] \rightarrow [2,\color{red}{3}] \rightarrow [2,1] $ .
In the second test case, array $ a $ will change in the following way:
$ [1,\color{red}{2},4] \rightarrow [\color{red}{1},6,4] \rightarrow [7,\color{red}{6},4] \rightarrow [\color{red}{7},2,4] \rightarrow [5,2,\color{red}{4}] \rightarrow [5,\color{red}{2},1] \rightarrow [\color{red}{5},3,1] \rightarrow [6,\color{red}{3},1] \rightarrow [\color{red}{6},2,1] \rightarrow [4,2,1] $
交换两个数,有一个经典的通过异或达到的方式。相信各位卡常高手应该都知道。
x^=y
y^=x
x^=y
简写完后就是 x^=y^=x^=y
拆成二进制后,发现每个二进制位都交换了,所以两个数可以成功交换。
所以,要实现交换,只要想办法使一个数 \(a_x^=a_y\) 就行了。
经过一波尝试,有这样一种方法:
10000
01000
00100
00010
00001
先异或一波
10000
11000
01100
00110
00011
然后把要异或上那个数移过来
10000
11000
10100
00110
00011
10000
11000
10100
10010
00011
10000
11000
10100
10010
10001
然后上面两种操作全部进行逆操作,将一切都变回去,就成功让一个数异或上另一个数,且其他数不变。
但是写完后跑了 400 时,出来的次数是 400000。大概多了一倍吧。
仔细观察上面的过程,会发现让一个数异或上另一个数用了 4 轮此操作,但是有两次操作是废的。那么如果我们把第一次操作完后反复使用。由于我们是要 \(a_x\oplus =a_y\),\(a_{x+1}\oplus=a_{y-1}\),所以可以比如说这样。
100000
110000
011000
001100
000110
000011
100000
110000
101000
100100
100010
100001
100000
010000
011000
001100
000110
100001
100000
010000
011000
010100
010010
100001
100000
010000
010000
010100
010010
100001
这样子就可以把常数除以2.
#include<cstdio>
const int N=405,M=3e5+5;
int n,m,st[M],k;
void run(int l,int r)
{
if(l>=r||l+1==r)
return;
for(int i=r-2;i>=l;i--)
st[++m]=i%n;
for(int i=l+1;i<r;i++)
st[++m]=i%n;
run(l+1,r-1);
}
void todo(int l,int r)
{
for(int i=l;i<r;i++)
st[++m]=i%n;
}
int main()
{
scanf("%d",&n);
k=n-2>>1;
todo(0,n-1);
run(0,n-1);
todo(n-1-k,n+k);
run(n-1-k,n+k);
todo(0,n-1);
run(0,n-1);
printf("%d\n",m);
for(int i=1;i<=m;i++)
printf("%d ",st[i]);
return 0;
}
标签:le,Xor,color,CF1748F,int,Reversal,array,red,rightarrow
From: https://www.cnblogs.com/mekoszc/p/17065035.html