Description
给定一个长度为n的序列a,如果只允许进行比较和交换相邻两个数的操作,求至少需要多少次交换才能把a从小到大排序.
Sol
只允许比较和交换相邻两个数,就是冒泡排序算法.
只有在前者大于后者的时候才会交换相邻两个数,也就是每交换一次逆序对就减少一个
最后序列排序完毕后,逆序对的总数为0
所以最小交换次数就是序列的逆序对个数(归并排序求逆序对个数
Code
#include<iostream> #include<cstdio> #define il inline #define Rg register #define go(i,a,b) for(Rg int i=a;i<=b;i++) #define yes(i,a,b) for(Rg int i=a;i>=b;i++) #define ll long long using namespace std; il int read() { int x=0,y=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();} while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();} return x*y; } const int N=500001; int n,a[N],b[N]; ll as; il void sol(int l,int r) { if(l==r)return; int mid=(l+r)>>1; sol(l,mid);sol(mid+1,r); Rg int i=l,j=mid+1; go(k,l,r) { if((a[i]<a[j]&&i<=mid) || j>r)b[k]=a[i++]; else b[k]=a[j++],as+=mid-i+1; } go(k,l,r)a[k]=b[k]; } int main() { while(1) { n=read();as=0; if(!n)break; go(i,1,n)a[i]=read(); sol(1,n); printf("%lld ",as); } return 0; }