2024.11.14 鲜花
双调排序的正确性证明暨第八交响曲题解
推歌:Double Agent
好多题解都写的或多或少有问题(包括那篇
首先给出双调序列的定义:满足一下条件之一的序列
即是单谷。- 其可以通过循环位移满足 1
注意到根据定义 1,2,8,7,6,5,4,3
。
upd:这个 hack 是双调,或者说所有的单峰和单谷都是双调,hack 的地方是将它拆开后 1,2,4,3|6,5,8,7
中 6,5,8,7
不是单峰或单谷,但它是双调
过程不再解释,但是需要指出的是,双调序列满足从中间分成相等两段后依次经过 Batcher 比较器(即 Compare And Swap
操作)后满足左右两段都是双调序列并且左边所有值都小于右边所有值,并不需要重新构造。
如果这个结论是真的,那么整个算法的正确性是显然的,考虑证明这个结论。
首先应用高德纳的
证明大致就是考虑二进制分解,其对于每一位都能排对。
upd:贺了一个好像更正规的证明
考虑其逆否命题:任何不正确的排序网络都可以构造一种
考虑一个可以使其错误的序列
考虑一对一样的数可以视为交换,也可以视为不交换,所以将他扔进这个排序网络中可以视为其依然只交换原来的交换,
考虑一个双调的
对于没有
然后考虑分讨
-
形如
的序列,即 是连续一段:-
即划分到 和 中间:容易发现其左边一定是前缀,右面一定是后缀,所以若两边的按位与不为
,则经过交换后右边一定是连续的一段 ,左边经过将一定后缀变成 也一定最多存在一段连续的 ,满足定义。若按位或是
,其左边一定是 ,右边一定是一段前缀加一段后缀。 -
即没有划分到 和 中间:容易发现其经过交换后右边一定是连续的一段
,左边一定全是 ,满足定义。
-
类似分讨
Code
#include<bits/stdc++.h> using namespace std; using llt=long long; using llf=long double; using ull=unsigned long long; #define endl '\n' #ifdef LOCAL FILE *InFile=freopen("in_out/in.in","r",stdin),*OutFile=freopen("in_out/out.out","w",stdout); #else FILE *InFile=freopen("symphony.in","r",stdin),*OutFile=freopen("symphony.out","w",stdout); #endif const int N=203; int n,md; struct V{int l,r,d; V(int a,int b,int c):l(a),r(b),d(c){}}; vector<V> aas[13]; void Srt(int l,int r,int d,vector<V> &c){ if(l==r) return ; else{ int mid=l+r>>1; for(int a=l,b=mid+1;a<=mid&&b<=r;++a,++b) c.emplace_back(a,b,d); Srt(l,mid,d+1,c),Srt(mid+1,r,d+1,c); } } void PSrt(int l,int r,int d,vector<V> &c){ int mid=l+r>>1; for(int a=mid,b=mid+1;b<=r&&a>=l;--a,++b) c.emplace_back(a,b,d); Srt(l,mid,d+1,c),Srt(mid+1,r,d+1,c); } void Slv(int l,int r,int d){ if(l==r) return ; else{ int mid=l+r>>1; md=max(md,d); Slv(l,mid,d+1),Slv(mid+1,r,d+1); PSrt(l,r,0,aas[d]); } } int main(){ ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr); cin>>n; int r=1; while(r<n) r<<=1; Slv(1,r,1); int cnt=0; for(int i=md;i;--i){ sort(aas[i].begin(),aas[i].end(),[](const V &a,const V &b){return a.d<b.d;}); int la=0; for(auto k:aas[i]) if(k.r<=n) if(la!=k.d) ++cnt,la=k.d; ++cnt; } cout<<cnt<<endl; for(int i=md;i;--i){ int la=0; for(auto k:aas[i]) if(k.r<=n){ if(la!=k.d) cout<<endl,la=k.d; cout<<"CMPSWP R"<<k.l<<" R"<<k.r<<' '; } cout<<endl; } }
P
本文来自博客园,作者:5k_sync_closer,转载请注明原文链接:https://www.cnblogs.com/xrlong/p/18546751
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0) 进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了