火柴排队 题解
题目关键点
这道题其实就是一道求 逆序对 的题
那为什么是求逆序对呢?
我们来分析一下题目:
题目要求交换完以后要
拆分得
因为
那当
那如何取最大值?
这里先给出一个策略(证明放在后面):
对于数列
或者上面公式中
其实上面公式中所表示的含义就是 顺序之乘
接下来证明一下 如果有人直接想看代码可以 跳过(bushi
设升序数列 其中
推论过程,先给出一个结论:
证明这个结论: 因此该公式成立
推广该结论到整个数列中,乱序之乘就相当于不断将交换顺序打乱的过程,最终符合该结论的标准,最终得出 顺序之乘 乱序之乘,证毕
那么,证明好这个结论,我们继续往下看
由题目要
那最小距离就出来了,可是我们怎么求出最小交换次数呢?
我们举一个例子 其实就是样例1:
4 2 3 1 4 3 2 1 4
我们由样列知,
对两个数组分别从小到大排序,得
信息 |
||
---|---|---|
排序过后的值 | ||
该数组中该值对应的原数组的编号 |
我们来依次处理一下:
首先看
再来看一下
这里,产生了不符合原则的数对,所以我们可以另外定义一个数组
我们看一下
首先,设
还是以上面的样例为例,操作是这样的:
- 所以
,逆序对个数为 (交换 与 ) 看,这就是 排序 的魅力!
为什么上述操作能够实现?
因为产生了 逆序:只要原序列中的
求逆序对有多种方法:冒泡、归并、树状数组等
这里由于 本蒟蒻太菜,只会冒泡和归并,冒泡又会超时,所以用归并写的
如果不知道归并或想用树状数组写可以自行 出门右转 百度
好了,那么思路就推导完了,接下来如果读者已经懂了可以自己尝试写一下
如果还想看代码,也可以往后面看(bushi
代码实现
本部分将分步骤写成
定义与模板
这部分比较简单,代码里有注释
//#pragma GCC optimize(3) //#pragma GCC optimize(2) //上方是O(2)与O(3)的优化,如果超时可以尝试开一下(但是本程序不会) //要注意的是,上方代码不可以再洛谷取消注释后提交,不然会CE(别问我怎么知道的) #include<bits/stdc++.h>//万能头 using namespace std;//命名空间 const int mod=99999997;//按题目定义的模数 int n,ans=0;//ans指最少要交换几次 struct match{//定义结构体match(火柴) int high,id;//high指火柴高度,id指火柴排序后在原来数列的编号 inline bool operator < (const match &temp)//重载运算符,不会的自己百度 const{return high<temp.high;}//按照高度从小到大排序 }a[100009],b[100009]; int ma[100009],temp[100009];//ma的定义在上文,temp是对ma归并排序时的临时数组 int main() { ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); //玄学的cin,cout优化 return 0; }
预处理
预处理包含输入、离散化、排序、初始化好
//#pragma GCC optimize(3) //#pragma GCC optimize(2) #include<bits/stdc++.h> using namespace std; const int mod=99999997; int n,ans=0; struct match{ int high,id; inline bool operator < (const match &temp) const{return high<temp.high;} }a[100009],b[100009]; int ma[100009],temp[100009]; int main() { ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); cin>>n; for(int i=1;i<=n;i++) cin>>a[i].high,a[i].id=i; for(int i=1;i<=n;i++) cin>>b[i].high,b[i].id=i;//输入,由于数据太大,需要离散化 sort(a+1,a+n+1),sort(b+1,b+n+1);//对火柴排序 for(int i=1;i<=n;i++) ma[b[i].id]=a[i].id;//ma的用法上问所示 return 0; }
归并排序求逆序对及输出
归并排序……都写到
不过如果想知道归并排序可以看看 这些
只是模板罢了
//#pragma GCC optimize(3) //#pragma GCC optimize(2) #include<bits/stdc++.h> using namespace std; const int mod=99999997; int n,ans=0; struct match{ int high,id; inline bool operator < (const match &temp) const{return high<temp.high;} }a[100009],b[100009]; int ma[100009],temp[100009]; inline void Sort(int l,int r)//归并排序模板,我就不多说了 { if(l>=r) return; int mid=(l+r)>>1; Sort(l,mid),Sort(mid+1,r); int i=l,j=mid+1,k=l; while(i<=mid&&j<=r) { if(ma[i]<=ma[j]) temp[k++]=ma[i++]; else temp[k++]=ma[j++],ans+=(mid-i+1)%mod,ans%=mod; } while(i<=mid) temp[k++]=ma[i++]; while(j<=r) temp[k++]=ma[j++]; for(int point=l;point<=r;point++) ma[point]=temp[point]; return; } int main() { ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); cin>>n; for(int i=1;i<=n;i++) cin>>a[i].high,a[i].id=i; for(int i=1;i<=n;i++) cin>>b[i].high,b[i].id=i; sort(a+1,a+n+1),sort(b+1,b+n+1); for(int i=1;i<=n;i++) ma[b[i].id]=a[i].id; Sort(1,n);//对ma进行归并 cout<<ans;//输出,不需要我讲了吧 return 0; }
最终无注释 高清 代码
这个我就不放在这里了吧,毕竟前面已经演示过很多次了
想知道的可以看 这里
总结
知识点:不等式、归并求逆序对、离散化等
题目涉及知识点不难,只是要慢慢细心地推,发现求逆序对的 本质
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~