火柴排队 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为: ,其中 ai表示第一列火柴中第 i 个火柴的高度,bi表示第二列火柴中第 i 个火柴的高度。 每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997 取模的结果。
输入描述 Input Description 共三行,第一行包含一个整数 n,表示每盒中火柴的数目。 第二行有 n 个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。 第三行有 n 个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。
输出描述 Output Description 输出共一行,包含一个整数,表示最少交换次数对 99,999,997 取模的结果。
样例输入 Sample Input [Sample 1] 4 2 3 1 4 3 2 1 4 [Sample 2] 4 1 3 4 2 1 7 2 4
样例输出 Sample Output [Sample 1] 1 [Sample 2] 2
数据范围及提示 Data Size & Hint 【样例1说明】 最小距离是 0,最少需要交换 1 次,比如:交换第 1 列的前 2 根火柴或者交换第 2 列的前 2 根火柴。 【样例2说明】 最小距离是 10,最少需要交换 2 次,比如:交换第 1 列的中间 2 根火柴的位置,再交换第 2 列中后 2 根火柴的位置。 【数据范围】 对于 10%的数据, 1 ≤ n ≤ 10; 对于 30%的数据,1 ≤ n ≤ 100; 对于 60%的数据,1 ≤ n ≤ 1,000; 对于 100%的数据,1 ≤ n ≤ 100,000,0 ≤火柴高度≤ 2^31 - 1。
PS:上面的两列火柴之间的距离没显示出来,是Σ(ai-bi)^2(i:1~n)
思路 这道题属于正解比较难想的一类,不过在做这类题的时候要紧扣题目,仔细分析题目所给的条件,说不定就能发现端倪。 废话不多说,首先根据题目意思,Σ(ai-bi)^2=Σ(ai^2+bi^2)-2Σai*bi,其中, Σ(ai^2+bi^2)为定值,要让距离最小,必要使Σai*bi最大。这里需要用排序不等式,简而言之,就是两个长度相同的有序序列a,b,有a1*b1+a2*b2+……+an*bn能使Σai*bi最大,恩恩。然后先做一遍排序,使两个序列有序,然后由每个火柴原来的位置来反推交换步数,实际上就是个求逆序对的过程 PS:如果暴力的话则不必想太多,不过这里写的是正解代码QAQ。另外排序不等式貌似是数学奥赛的东西???
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> using namespace std; typedef long long ll; const int maxn=100000+5; struct node{ int num,pos; }a[maxn],b[maxn]; const int mod=99999997; bool cmp(node x,node y) { return x.num<y.num; } int A[maxn],T[maxn]; int ans=0; void merge(int l,int mid,int r) { int i=l,j=mid+1,k=l-1; while(i<=mid&&j<=r) { if(A[i]>A[j]) { ans+=mid-i+1; ans%=mod; T[++k]=A[j],j++; } else T[++k]=A[i],i++; } while(i<=mid) T[++k]=A[i],i++; while(j<=r) T[++k]=A[j],j++; for(int p=l;p<=r;p++) A[p]=T[p]; } void mesort(int l,int r) { if(l==r) return; int mid=(l+r)>>1; mesort(l,mid); mesort(mid+1,r); merge(l,mid,r); } int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i].num); a[i].pos=i; } for(int i=1;i<=n;i++) { scanf("%d",&b[i].num); b[i].pos=i; } sort(a+1,a+1+n,cmp); sort(b+1,b+1+n,cmp); for(int i=1;i<=n;i++) { A[a[i].pos]=b[i].pos; } mesort(1,n); printf("%d\n",ans%mod); return 0; }