NOIP2013火柴排队
2017-10-26 19:26
232 查看
http://codevs.cn/problem/3286/
思路
首先易知,当a,b两串都进行过排序后,各对应位置的差值平方之和最小。
简单证明:
设序列只有两个数分别是a,b;c,d;且a < b;c < d
设S1=(a-c)^2+(b-d)^2,S2=(a-d)^2+(b-c)^2,
S1-S2=2ad+2bc-2ac-2bd=2a(d-c)+2b(c-d)=2(c-d)(b-a)<0
S1 < S2。
若存在a=b或c=d的情况S1仍为最小距离。
那么问题就转化成了,已知a串 b串对应位置,每次交换b中相邻的两个数,求最小的移动步数使b串各位置与a串一一对应。
交换过程类似于冒泡排序,我们知道冒泡排序每次交换都会使原串逆序对数减少1,则交换次数 = b串相对于a串的逆序对数(以a串对应b串位置的大小关系为比较标准)。统计逆序对数即可。
代码
思路
首先易知,当a,b两串都进行过排序后,各对应位置的差值平方之和最小。
简单证明:
设序列只有两个数分别是a,b;c,d;且a < b;c < d
设S1=(a-c)^2+(b-d)^2,S2=(a-d)^2+(b-c)^2,
S1-S2=2ad+2bc-2ac-2bd=2a(d-c)+2b(c-d)=2(c-d)(b-a)<0
S1 < S2。
若存在a=b或c=d的情况S1仍为最小距离。
那么问题就转化成了,已知a串 b串对应位置,每次交换b中相邻的两个数,求最小的移动步数使b串各位置与a串一一对应。
交换过程类似于冒泡排序,我们知道冒泡排序每次交换都会使原串逆序对数减少1,则交换次数 = b串相对于a串的逆序对数(以a串对应b串位置的大小关系为比较标准)。统计逆序对数即可。
代码
//归并排序求逆序对——O(nlogn)AC #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; const int mod = 99999997; int n,ans1,ans2; int A[1000010],B[1000010],As[1000010],Bs[1000010],mp[1000010],pos[1000010],tmp[1000010]; void merge_sort(int l,int r) { if(l==r) return; int mid=(l+r)>>1; merge_sort(l,mid); merge_sort(mid+1,r); int i=l; int k=l; int j=mid+1; while(i<=mid&&j<=r) { if(pos[mp[B[i]]]>pos[mp[B[j]]]) { tmp[k++]=B[j++]; ans2=((ans2%mod)+((mid-i+1)%mod))%mod;//在从i开始到mid中的所有数都会与j位置的数形成一个逆序对 } else tmp[k++]=B[i++]; } while(i<=mid) tmp[k++]=B[i++]; while(j<=r) tmp[k++]=B[j++]; for(int i=l;i<=r;i++) B[i]=tmp[i]; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&A[i]); As[i]=A[i]; pos[A[i]]=i;//按编号比较 } for(int i=1;i<=n;i++) { scanf("%d",&B[i]); Bs[i]=B[i]; } sort(As+1,As+n+1); sort(Bs+1,Bs+n+1); for(int i=1;i<=n;i++) { ans1+=(As[i]-Bs[i])*(As[i]-Bs[i]); mp[Bs[i]]=As[i];//最佳映射方案 } merge_sort(1,n); printf("%d",ans2); return 0; }
//冒泡排序求逆序对——O(n^2)会导致TLE #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; const int mod = 99999997; int n,ans1,ans2; int A[1000010],B[1000010],As[1000010],Bs[1000010],mp[1000010],pos[1000010]; bool flag; void bubble_sort(int l,int r) { for(int i=1;i<=n;i++) { for(int j=1;j<=n-i;j++) { if(pos[mp[B[j]]]>pos[mp[B[j+1]]]) { swap(B[j],B[j+1]);//每进行一次交换,逆序对的个数减少1 ans2++; flag=1; } } if(!flag) break; flag=0; } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&A[i]); As[i]=A[i]; pos[A[i]]=i;//按编号比较 } for(int i=1;i<=n;i++) { scanf("%d",&B[i]); Bs[i]=B[i]; } sort(As+1,As+n+1); sort(Bs+1,Bs+n+1); for(int i=1;i<=n;i++) { ans1+=(As[i]-Bs[i])*(As[i]-Bs[i]); mp[Bs[i]]=As[i];//最佳映射方案 } bubble_sort(1,n); printf("%d",ans2); return 0; }
相关文章推荐
- Noip2013 Day1 T2 火柴排队(归并排序/树状数组 求逆序对)
- NOIP 2013 火柴排队 (证明+乱搞之后的逆序对)
- 【NOIP2013提高组】火柴排队
- NOIP提高组2013 火柴排队
- 归并排序求逆序对 CODEVS 1688 && NOIP 2013 火柴排队
- noip2013 火柴排队 树状数组
- 【洛谷P3370】【NOIP2013】 火柴排队
- 【noip 2013】火柴排队
- NOIP2013 火柴排队
- [NOIP2013]火柴排队
- [noip2013tg] 火柴排队
- NOIP2013提高组 B.火柴排队 (逆序对)
- 【NOIP 2013 DAY.1】火柴排队【codevs 3286】
- 【noip2013提高组】火柴排队 树状数组+逆序对
- NOIP2013火柴排队
- [NOIP2013]火柴排队
- 洛谷 1966 [NOIP2013] 火柴排队 逆序对
- [noip2013]火柴排队 题解
- 【NOIP】提高组2013 火柴排队
- NOIP 2013 T2 火柴排队 ---->求逆序对