当$s=0$时(求最小值):
若$x_{0},x_{1},...,x_{n-1}$和$y_{0},y_{1},...,y_{n-1}$像题中所给的方式存储在$r[0][0..nk-1]$和$r[1][0..nk-1]$,那么执行
not(2,1),add(2,0,2),xor(2,0,2),xor(2,1,2),right(2,2,k) store(3,[1,0,0,...,0,1,0,0,...,0,......]),and(2,2,3) left(3,2,1),or(2,2,3) left(3,2,2),or(2,2,3) …… left(3,2,2^{L-2}),or(2,2,3) left(3,2,k-2^{L-1}),or(2,2,3) not(3,2),and(2,0,2),and(3,1,3),or(0,2,3)
(其中第2行$store$中1的位置为所有$k$的倍数,第7行$L=\lceil\log_{2}k\rceil$)
即可将$\min(x_{i},y_{i})$像题中所给的方式存储在$r[0][0..nk-1]$
操作次数为$2L+11$,预处理第二步$store$,当$k=10$时为$18+1$(后者的1指全局)
由此进行分治,即每一次将前$\lceil\frac{n}{2}\rceil$个和后$\lceil\frac{n}{2}\rceil$个取$\min$使得$n‘=\lceil\frac{n}{2}\rceil$,直至$n=1$即为答案
操作次数为$19\lceil\log_{2}n\rceil+1$,当$n=100$时为134,可以通过
当$s=1$时(排序):
类似前面取$\min$,我们可以构造"检查-交换"操作,只需要将最后一行修改为
not(3,2),and(4,0,2),and(5,1,3),and(6,0,3),and(7,1,2),or(0,4,5),or(1,6,7)
即可将$\min(x_{i},y_{i})$存储在$r[0][0...nk-1]$,将$\max(x_{i},y_{i})$存储在$r[1][0..nk-1]$
操作次数为$2L+14$,预处理第二步$store$,当$k=10$时为21+1
由于要先确定交换的位置(而不是根据数值交换),那么通常的排序算法中只有冒泡和选择可以支持,但两者的交换次数都为$o(n^{2})$,无法通过
注意到上述过程支持同时交换多个不同的数,此时有一个更为优秀的奇偶移项排序,伪代码如下:
i=1..(n+1)/2 j=1..n/2 swap(a[2j-1],a[2j]) j=1..(n-1)/2 swap(a[2j],a[2j+1])
(其中$a_{i}$下标从1到$n$,/2都指下取整,swap指"检查-交换"操作)
两次$j$的循环,实际上都可以用一次交换代替,那么交换次数即降为$o(n)$
具体实现,只需要将奇数位和偶数位分别取出,并且高位要补0避免0被交换到较小处
操作次数为$48\lceil\frac{n+1}{2}\rceil+5$,当$n=100$时为2405,可以通过
1 #include<bits/stdc++.h> 2 #include"registers.h" 3 using namespace std; 4 #define B 2000 5 int n,k,L; 6 void get_min(){ 7 append_not(2,1); 8 append_add(2,0,2); 9 append_xor(2,0,2); 10 append_xor(2,1,2); 11 append_right(2,2,k); 12 append_and(2,2,99); 13 for(int i=0;i<L-1;i++){ 14 append_left(3,2,(1<<i)); 15 append_or(2,2,3); 16 } 17 if (L)append_left(3,2,k-(1<<L-1)); 18 append_or(2,2,3); 19 append_not(3,2); 20 append_and(2,0,2); 21 append_and(3,1,3); 22 append_or(0,2,3); 23 } 24 void swap(int x,int y){ 25 append_not(2,1); 26 append_add(2,0,2); 27 append_xor(2,0,2); 28 append_xor(2,1,2); 29 append_right(2,2,k); 30 append_and(2,2,99); 31 for(int i=0;i<L-1;i++){ 32 append_left(3,2,(1<<i)); 33 append_or(2,2,3); 34 } 35 if (L)append_left(3,2,k-(1<<L-1)); 36 append_or(2,2,3); 37 append_not(3,2); 38 append_and(4,0,2); 39 append_and(5,1,3); 40 append_and(6,0,3); 41 append_and(7,1,2); 42 append_or(x,4,5); 43 append_or(y,6,7); 44 } 45 void calc0(){ 46 for(;n>1;n=((n+1)>>1)){ 47 append_right(1,0,(n>>1)*k); 48 get_min(); 49 } 50 } 51 void calc1(){ 52 vector<bool>v,v0,v1; 53 for(int i=0;i<B;i++)v.push_back((n*k<=i)); 54 append_store(98,v); 55 append_or(0,0,98); 56 for(int i=0;i<B;i++)v0.push_back(((i/k)&1)^1); 57 for(int i=0;i<B;i++)v1.push_back(((i/k)&1)); 58 append_store(96,v0); 59 append_store(97,v1); 60 for(int i=1;i<=((n+1)>>1);i++){ 61 append_and(1,0,97); 62 append_right(1,1,k); 63 append_and(0,0,96); 64 swap(0,1); 65 append_left(1,1,(k<<1)); 66 swap(1,0); 67 append_right(1,1,k); 68 append_or(0,0,1); 69 } 70 } 71 void construct_instructions(int p,int nn,int kk,int q){ 72 n=nn,k=kk,L=0; 73 while ((1<<L)<k)L++; 74 vector<bool>v; 75 for(int i=0;i<B;i++)v.push_back(i%k==0); 76 append_store(99,v); 77 if (!p)calc0(); 78 else calc1(); 79 }