A - Almost Correct 另一种相似的构造
Link
题意
给定 01 串 a1a2…an 长度为 n (n≤16)。构造一个排序网络,使其能恰好能排序除给定 01 串外的所有长度为 n 的 01 串。排序网络所需的步骤 m≤120。其中,排序网络指的是:给定 {(xm,ym)},i 按照 1 到 n 进行遍历,若 axi>ayi 则交换 axi,ayi 。
这不比官方题解写的清楚
一种构造方案
-
记所有 01 串 a 中 1 所在位置下标的集合 S 。找到 S 的最小值(即 01 串中 1 所在的最左侧位置),记为 cur。记 S 的元素个数(即 1 的个数)为 ∣S∣。
-
交换 cur 和 S 中的其他元素,即 ∀x∈S,(x,cur)。
-
对剩下的 01 串 {1,2,3,…,n}−{cur}={1,2,…cur−1,cur+1,…,n}
正常进行排序(参照冒泡排序),即去掉下标 cur 后对其他元素排序。
-
依次交换 (1,cur),(2,cur),…,(cur−1,cur),(cur,n−(∣S∣−1)−1)),(cur,n−(∣S∣−1)−2)),(cur,n−(∣S∣−1)−3)),…,(cur,cur+1))
面向萌新的解释与说明
以下内容,为方便理解,将争对给定串 a=001010110 进行举例说明。
-
记所有 01 串 a 中 1 所在位置下标的集合 S 。找到 S 的最小值(即 01 串中 1 所在的最左侧位置),记为 cur。记 S 的元素个数(即 1 的个数)为 ∣S∣。
-
首先,∣S∣=0;若 ∣S∣=0,则 01 串全由 0 组成,已经被排好序了。
-
对于给定串 a=001010110 ,cur=3,S={3,5,7,8},∣S∣=4。
-
交换 cur 和 S 中的其他元素,即 ∀x∈S,(x,cur)。
-
此步骤中,对于任意给定 01 串没有发生变化,例如给定串 a=001010110 进行了 (3,5),(3,7),(3,8) 的交换。
-
而对于非给定串 b :
情况 1:若对于任意位置 x∈S,bx=1,例如 b=001010111 ,则非给定串 b 没有发生变化。而非给定串 b 又与给定串 a 不完全相同,即 b 中 1 的个数 >∣S∣。
情况 2:若 bcur=0,例如 b=010010110 ,由于x∈S,x≥cur,所有交换都与 cur 右边的数进行交换,此时 b 也没有发生变化。
情况 3:若 bcur=1,存在x∈S,bx=0,例如 b=001010101 ,由于x∈S,x≥cur,所有交换都与 cur 右边的数进行交换,且有 bx=0,故此时 b 中 bcur=0。
总结:经过此操作后,要么 bcur=0,要么 bcur=1 且 b 中 1 的个数 >∣S∣。
-
此过程中用了 ∣S∣−1 步。
-
对剩下的 01 串 {1,2,3,…,n}−{cur}={1,2,…cur−1,cur+1,…,n}
正常进行排序(参照冒泡排序),即去掉下标 cur 后对其他元素排序。
-
此步骤中,对于给定串 a=001010110,除下标为 cur 的元素外进行冒泡排序后,得到 a′=001000111。
-
对于非给定串 b :
情况 1:bcur=0;此时要么 b′ 已经是排好序的,例如: b′=000011111;要么 b′ 是形如010111111,第 cur 位两边均为 1 且除了下标为 cur 已经是排好序的。
情况 2:bcur=1 且 b 中 1 的个数 >∣S∣;此时要么 b′ 是形如 001011111,其中原来 a′ 中最右侧的 0 在 b′ 中一定是 1 ,即第 n−(∣S∣−1) 位一定是 1 ;要么 b′ 已经是排好序的例如: b′=011111111。
总结: b′ 要么是已经排好序的,不继续考虑;要么 bcur′=0 且 bcur−1′=1 ;要么 bcur′=1 且 bn−(∣S∣−1)′=1。
-
此过程中用了 2(n−1)(n−2) 步。
-
依次交换 (1,cur),(2,cur),…,(cur−1,cur),(cur,n−(∣S∣−1)−1)),(cur,n−(∣S∣−1)−2)),(cur,n−(∣S∣−1)−3)),…,(cur,cur+1))
-
下标 n−(∣S∣−1) 表示为 a′ 最左侧 0 的位置。对于给定串 a′=001000111 ,最后的结果为 000010111,在下标为 n−(∣S∣−1),n−(∣S∣−1)−1 处是乱序的。
-
对于非给定串 b′ :
情况 1:bcur′=0 且 bcur−1′=1,形如 010111111,进行操作 (1,cur),(2,cur),…,(cur−1,cur) 可将最右侧的 0 移动到最左侧的 1 的左侧,即让结果为顺序的。
情况 2:bcur′=1 且 bn−(∣S∣−1)′=1,形如 001001111;进行操作 (1,cur),(2,cur),…,(cur−1,cur) 对 b′无影响;进行操作 (cur,n−(∣S∣−1)−1)),(cur,n−(∣S∣−1)−2)),(cur,n−(∣S∣−1)−3)),…,(cur,cur+1)) 可将最左侧的 1 移动到最右侧的 0 的右侧,即让结果为顺序的。
总结:非给定串 b 经过操作均是顺序的。
-
此过程中用了 n−(∣S∣−1)−1−1=n−∣S∣−1 步。
-
总计用了 ∣S∣−1+2(n−1)(n−2)+n−∣S∣−1=2(n−1)(n−2)+n−2 步,n=16 时最大值为 119≤120
这比官方题解好理解
Code
int ansx[300]={},ansy[300]={},cnt=0;
int a[20],n;read(n);
rep(i,1,n+1)scanf("%1lld",&a[i]);
int num=0,cur=10000;
rep(i,1,n+1)num+=a[i];
rep(i,1,n+1)if(a[i])ckmin(cur,i);
rep(i,1,n+1)if(i!=cur&&a[i]){
ansx[++cnt]=min(i,cur),ansy[cnt]=max(i,cur);
}
rep(i,1,n){
rep(j,1,n-i)ansx[++cnt]=(j>=cur?j+1:j),ansy[cnt]=(j+1>=cur?j+2:j+1);
}
rep(i,1,cur)ansx[++cnt]=i,ansy[cnt]=cur;
nrep(i,n-num,cur+1)ansx[++cnt]=cur,ansy[cnt]=i;
后记
写这篇题解,是为了铭记那些犯脑梗的我们。
此题,这是我们的输出(赛时,队友和我分别至少调了 1.5h,还没看出来):
if(cnt){
rep(i,1,cnt+1)print(ansx[i],' ');puts("");
rep(i,1,cnt+1)print(ansy[i],' ');puts("");
}
这是要求的输出:
In the i-th of the next m lines, print xi and yi (1≤xi<yi≤n) separated by a space.