杭電2017新生賽1006-稿件整理
阿新 • • 發佈:2019-02-18
稿件整理
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; } }