火柴排队
【题目描述】
涵涵有两盒火柴,每盒装有n根火柴,每根火柴都有一个高度。现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为:
,其中ai表示第一列火柴中第 i 个火柴的高度,bi表示第二列火柴中第i个火柴的高度。
每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对99999997取模的结果。
【输入描述】
共三行,第一行包含一个整数n,表示每盒中火柴的数目。
第二行有n个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。
第三行有n个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。
【输出描述】
输出共一行,包含一个整数,表示最少交换次数对99999997取模的结果。
【样例输入】
样例1:
4
2 3 1 4
3 2 1 4
样例2:
4
1 3 4 2
1 7 2 4
【样例输出】
样例1:
1
样例2:
2
【数据范围及提示】
样例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 ≤ 1000;
对于100%的数据,1 ≤ n ≤ 100000,0 ≤ 火柴高度 ≤ 2^31-1。
源代码: #include<cstdio> #include<algorithm> using namespace std; struct Node { int Sum,Num; }; Node i1[100001],i2[100001]; int n,ans(0),i[100001],h[100001]; bool Rule(Node t1,Node t2) { return t1.Sum>t2.Sum; } void Merge(int t1,int t2) //归并排序求逆序对。 { if (t1==t2) return; int t=(t1+t2)>>1,x=t1,y=t+1,num=t1; Merge(x,t); Merge(y,t2); while (x<=t&&y<=t2) if (i[x]>i[y]) { ans=(ans+t-x+1)%99999997; //凡事都要多动脑子,回溯上来啦,两段早就排好啦。 h[num++]=i[y++]; } else h[num++]=i[x++]; while (x<=t) h[num++]=i[x++]; while (y<=t2) h[num++]=i[y++]; for (int a=t1;a<=t2;a++) i[a]=h[a]; } int main() //恶心的预处理。 { scanf("%d",&n); for (int a=1;a<=n;a++) { scanf("%d",&i1[a].Sum); i1[a].Num=a; } for (int a=1;a<=n;a++) { scanf("%d",&i2[a].Sum); i2[a].Num=a; } sort(i1+1,i1+n+1,Rule); sort(i2+1,i2+n+1,Rule); for (int a=1;a<=n;a++) //杀死脑细胞。 i[i2[a].Num]=i1[a].Num; Merge(1,n); printf("%d",ans); return 0; } /* 举个例子: 5 3 2 1 4 5 5 2 1 4 3 那么在第二个序列中就有: 5应当排第5个; 2应当排第2个; 1应当排第3个; 4应当排第4个; 3应当排第1个; 排完序不就是解吗?问题转化为求52341的逆序对,共7步。 */