[蓝桥杯][历届试题]小朋友排队

时间限制: 1Sec 内存限制: 128MB 提交: 75 解决: 11

题目描述
n  个小朋友站成一排。现在要把他们按身高从低到高的顺序排列,但是每次只能交换位置相邻的两个小朋友。 

每个小朋友都有一个不高兴的程度。开始的时候,所有小朋友的不高兴程度都是0。 

如果某个小朋友第一次被要求交换,则他的不高兴程度增加1,如果第二次要求他交换,则他的不高兴程度增加2(即不高兴程度为3),依次类推。当要求某个小朋友第k次交换时,他的不高兴程度增加k。 

请问,要让所有小朋友按从低到高排队,他们的不高兴程度之和最小是多少。 

如果有两个小朋友身高一样,则他们谁站在谁前面是没有关系的。 

样例说明 
首先交换身高为3和2的小朋友,再交换身高为3和1的小朋友,再交换身高为2和1的小朋友,每个小朋友的不高兴程度都是3,总和为9。 
数据规模和约定 
对于100%的数据,1< =n< =100000,0< =Hi< =1000000。 

输入
输入的第一行包含一个整数n,表示小朋友的个数。 
第二行包含  n  个整数  H1  H2  …  Hn,分别表示每个小朋友的身高。
输出
输出一行,包含一个整数,表示小朋友的不高兴程度和的最小值。
样例输入
3 
3  2  1 
样例输出
9

#include<cstdio>
#define maxn 100010
struct data
{
    int num,cnt;
}A[maxn],temp[maxn];
int n;
//long long ans;
long long ANS[100];
void merge(int L1,int R1,int L2,int R2)
{
    int k=0,i=L1,j=L2;
    while(i<=R1 && j<=R2)
    {
        if(A[i].num<=A[j].num)
//如果A[i].num<A[j].num,则A[L2,j-1]的元素小于A[i],如果相等,则先存储上数组的元素,这个时候下数组的A[L2,j-1]仍然都满足小于A[i].num { A[i].cnt+=j-L2; temp[k++]=A[i++]; } else if(A[i].num>A[j].num)//A[i,R1]都大于A[j] { A[j].cnt+=R1-i+1; temp[k++]=A[j++]; } } //剩下上数组,那么剩下的元素都要移动下数组的元素个数 while(i<=R1) { A[i].cnt+=R2-L2+1; temp[k++]=A[i++]; } while(j<=R2) temp[k++]=A[j++]; //剩下下数组,就不需要移动 for(i=0;i<k;i++) A[L1+i]=temp[i]; } void mergeSort(int L,int R) { if(L<R) { int mid = (L+R)/2; mergeSort(L,mid); mergeSort(mid+1,R); merge(L,mid,mid+1,R); } } int main(void) { //FILE *in = fopen("input10.txt","r"); //fscanf(in,"%d",&n); //for(int i=0;i<n;i++) fscanf(in,"%d",&(A[i].num)); scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&(A[i].num)); mergeSort(0,n-1); for(int i=0;i<n;i++) { long long s = A[i].cnt; //ans+=s*(s+1)/2; ANS[1]+=s*(s+1)/2; int length=1; while(ANS[length]/10!=0) { ANS[length+1]+=ANS[length]/10; ANS[length]%=10; length++; } if(ANS[0]<length) ANS[0]=length; } //printf("%lld",ans); for(int i=ANS[0];i>=1;i--) printf("%d",ANS[i]); //printf("\n"); return 0; }

大致的思路:使用归并排序的思想求逆序对的思想,划分成为一个上数组,一个数组。
      上数组的元素往下数组方向移动,下数组的元素往上数组方向移动。
      上数组的元素往下数组方向移动,移动的长度是下数组中小于该元素的个数;
      下数组的元素往桑数组方向移动,移动的长度是上数组中大于该元素的个数。
      在结构体中记录移动的次数。
      由于数据较大,可以使用高精度加法进行计算。

 

 

注意:这里使用long long 也是可以的

#include<cstdio>
#define maxn 100010
struct data
{
    int num,cnt;
}A[maxn],temp[maxn];
int n;
long long ans;
long long ANS[100];
void merge(int L1,int R1,int L2,int R2)
{
    int k=0,i=L1,j=L2;
    while(i<=R1 && j<=R2)
    {
        if(A[i].num<=A[j].num)//如果A[i].num<A[j].num,则A[L2,j-1]的元素小于A[i],如果相等,则先存储上数组的元素,这个时候下数组的A[L2,j-1]仍然都满足小于A[i].num 
        {
            A[i].cnt+=j-L2;
            temp[k++]=A[i++];
        }
        else if(A[i].num>A[j].num)//A[i,R1]都大于A[j] 
        {
            A[j].cnt+=R1-i+1;
            temp[k++]=A[j++];
        }
    }
    //剩下上数组,那么剩下的元素都要移动下数组的元素个数
    while(i<=R1) 
    {  
        A[i].cnt+=R2-L2+1;
         temp[k++]=A[i++]; 
    }     
    while(j<=R2) temp[k++]=A[j++]; //剩下下数组,就不需要移动 
    for(i=0;i<k;i++) A[L1+i]=temp[i];
}
void mergeSort(int L,int R)
{
    if(L<R)
    {
        int mid = (L+R)/2;
        mergeSort(L,mid);
        mergeSort(mid+1,R);
        merge(L,mid,mid+1,R);
    }
}
int main(void)
{    
    FILE *in = fopen("input10.txt","r");
    fscanf(in,"%d",&n);
    for(int i=0;i<n;i++) fscanf(in,"%d",&(A[i].num));
    //scanf("%d",&n);
    //for(int i=0;i<n;i++) scanf("%d",&(A[i].num));
    mergeSort(0,n-1);
    for(int i=0;i<n;i++)
    {
        long long s = A[i].cnt; 
        ans+=s*(s+1)/2;
    }
    printf("%lld",ans);
    
    return 0;
}

 

posted @ 2018-04-06 15:54  最美遇见你  阅读(277)  评论(0编辑  收藏  举报