[loj3528]位移寄存器

当$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 }
View Code

 

posted @ 2021-07-14 08:41  PYWBKTDA  阅读(53)  评论(0编辑  收藏  举报