1. 程式人生 > >杭電2017新生賽1006-稿件整理

杭電2017新生賽1006-稿件整理

稿件整理

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 294    Accepted Submission(s): 21


Problem Description 面對每天敲程式碼找Bug的日子,小Q實在受夠了,他決定放棄現在的IT技術崗位,追隨自己的內心,重拾兒時的文學夢。

於是,他應聘到《中國夢月報》當了一名編輯。

一天,小Q和他的小夥伴們在核對刊物初稿,但是一位編輯不小心把稿件弄亂了——編輯可能將正反面弄反了,也可能將前後張打亂了!

稿件每面有一個頁碼,頁碼1總為正面,總頁數n總為偶數。現在,假設只能通過正反面的翻轉與前後張的交換來整理稿件,並且正反面的翻轉與前後張的交換都算作一次整理。

給出當前的頁碼順序,請問最少經過幾次整理,才能將稿件的頁碼恢復升序?

特別說明:在一次操作中,前後頁交換時不可以同時翻轉奇偶面。
Input 輸入包含多組測試用例。

每組資料第一行輸入總頁數n(1<=n<=100000),接下去的一行輸入n個數(1~n),表示當前的頁碼順序。

每兩組輸入之間有一空行。
Output 每組輸出佔一行,輸出一個整數,表示需要的最少整理次數。
Sample Input 4 3 4 2 1 2 1 2
Sample Output 2 0 輸入時先判斷正反面,儲存一半的數字做前後交換,前後交換最小次數即為逆序數

直接求會超時,所以歸併求逆序數,與正反面相加即為答案。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int a[100005];
long long int ans;
void merge(int s1,int e1,int s2,int e2){
    int p1,p2,p;
    int* temp = new int[e2-s1+5];
    p=0;p1=s1;p2=s2;
    while(p1<=e1&&p2<=e2){
        if(a[p1]<=a[p2]){
            temp[p++]=a[p1++];
            continue;
        }else{
            temp[p++]=a[p2++];
            ans+=e1-p1+1; 
            continue;
        }
    }
    while(p1<=e1) temp[p++]=a[p1++];
    while(p2<=e2) temp[p++]=a[p2++];
    int i;
    for(i=s1;i<=e2;i++) a[i]=temp[i-s1];
    delete temp;
}

void merge_sort(int s,int e){
    int m;
    if(s<e){
        m=(s+e)/2;
        merge_sort(s,m);
        merge_sort(m+1,e);
        merge(s,m,m+1,e);
    }
}

int main(){
    int n;
    int num;
    while(cin>>n){
        ans=0;
        long long int step=0;
        for(int i=0;i<n;i++){
            cin>>num;
            if(i%2){
                if(num%2)step++;
            }else a[i/2]=num;
        }
        merge_sort(0,n/2-1);
        step+=ans;
        cout<<step<<endl;
    }
}