归并排序
运用了分治的思想,将一个数组分成几乎相等的两份,分别将两段中第一个最小的数拿出来放在一个临时数组中,直到全部取完。因为是递归的,所以每一段的数列都是排序好的。
void merge_sort(ll *A,ll *B,int x,int y) { if(y-x<=1)return; int m=x+(y-x>>1); int p=x,q=m,i=x; merge_sort(A,B,x,m); merge_sort(A,B,m,y); while(p<m or q<y) { if(q>=y or (p<m and A[p]<=A[q]))B[i++]=A[p++]; else B[i++]=A[q++]; } for(int i=x;i<y;i++)A[i]=B[i]; }
(没验证,有错误请指出)
这段代码中左端为闭,右端为开。因此调用时要将右端点+1
O(nlogn)
它有一个神奇的应用:求逆序对(的和)!因为我们发现每次递归时左边的还没有入列的数都是大于右边的数的,所以我们只要在else句的后面加上ans+=m-p就好辣!
#include<iostream> #include<cstdio> using namespace std; typedef long long ll; template <typename T> inline T read() { int w=0;T x=0;char c=getchar(); while(!isdigit(c))w|=c=='-',c=getchar(); while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar(); return w?-x:x; } const int maxn=5e5+10; int n; ll A[maxn],B[maxn],ans; void merge_sort(ll *A,ll *B,int x,int y) { if(y-x<=1)return; int mid=x+(y-x)/2; int p=x,q=mid,i=x; merge_sort(A,B,x,mid); merge_sort(A,B,mid,y); while(p<mid or q<y) { if(q>=y or (p<mid and A[p]<=A[q]))B[i++]=A[p++]; else B[i++]=A[q++],ans+=mid-p; } for(int i=x;i<y;i++)A[i]=B[i]; } int main() { n=read<int>(); for(int i=1;i<=n;i++)A[i]=read<ll>(); merge_sort(A,B,1,n+1); printf("%lld\n",ans); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现