P1327 数列排序
题目描述
给定一个数列{an},这个数列满足ai≠aj(i≠j),现在要求你把这个数列从小到大排序,每次允许你交换其中任意一对数,请问最少需要几次交换?
输入输出格式
输入格式:
第一行,正整数n (n<=100,000)。
以下若干行,一共n个数,用空格分隔开,表示数列{an},任意-2^31<ai<2^31-1。
输出格式:
只有一行,包含一个数,表示最少的交换次数。
输入输出样例
输入样例#1:
复制
8 8 23 4 16 77 -5 53 100
输出样例#1:
复制
5
逆序对??
看到这个题两个交换,交换次数,想到的应该是逆序对吧
然而并不对,因为逆序对是相邻的两个交换,这个题说的是任意两个交换,因此我们不能太过于主观臆断
逆序对10分
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define N 100010 using namespace std; int n,ans,a[N],b[N],tmp[N]; int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x*f; } void gsort(int l,int r) { if(l==r) return ; int mid=(l+r)>>1; gsort(l,mid); gsort(mid+1,r); int i=l,k=l,j=mid+1; while(i<=mid&&j<=r) { if(a[i]<=a[j]) b[k++]=a[i++]; else b[k++]=a[j++],ans+=mid-i+1; } while(i<=mid) b[k++]=a[i++]; while(j<=r) b[k++]=a[j++]; for(i=l;i<=r;i++) a[i]=b[i]; } int main() { n=read(); for(int i=1;i<=n;i++) a[i]=read(); gsort(1,n); printf("%d",ans); return 0; }
贪心,遇到跟排序后不一样的就把他交换
使用map
#include<map> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define N 100010 using namespace std; map<int,int>f; int n,ans,x,a[N],b[N]; int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x*f; } int main() { n=read(); for(int i=1;i<=n;i++) a[i]=read(),b[i]=a[i],f[b[i]]=i; sort(b+1,b+1+n); for(int i=1;i<=n;i++) { if(a[i]==b[i]) continue; ans++,x=f[b[i]]; f[a[i]]=x; a[x]=a[i]; } printf("%d",ans); return 0; }