「UVA10810」 Ultra-QuickSort 解題報告
阿新 • • 發佈:2018-12-17
題面
看不懂?!
大概的意思就是:
給出一個長度為n的序列,然後每次只能交換相鄰的兩個數,問最小需要幾次使序列嚴格上升
不斷讀入n,直到n=0結束
思路:
交換相鄰的兩個數,這不就類似氣泡排序嗎?但是n<500000
~~算了吧,我回去頹A+B ~~
於是我們就發現用氣泡排序直接計算次數是行不通的
但我們要知道:
氣泡排序的交換次數就是序列的逆序對數!!!
所以——就簡單了吧~
如何求逆序對?
1、歸併排序
思想是分治法
不斷劃分為兩小段
然後依次由小序列合併為大序列,同時求出逆序數
2、樹狀陣列
因為樹狀陣列的修改查詢是log級的所以可以使用(字首和的方法),沒學的建議先去學習一下,不是很難
Code:
#include<bits/stdc++.h> #define ll long long using namespace std; struct node{ int x,i; }a[500010]; int n; int b[500010]; int f[500010]; ll ans; int read() { int s=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { s=(s<<1)+(s<<3)+c-'0'; c=getchar(); } return s; } void update(int x)//修改 { for(;x<=n;x+=x&(-x)) f[x]++; return; } ll sum(int x)//求字首和 { ll res=0; for(;x;x-=x&(-x)) res+=f[x]; return res; } bool cmp(node a,node b) { return a.x>b.x; } int main() { int i,j; n=read(); while(n) { ans=0; memset(f,0,sizeof(f)); for(i=1;i<=n;i++) { a[i].x=read(); a[i].i=i; } sort(a+1,a+n+1,cmp); for(i=1;i<=n;i++)//先hash一下,按數值給其標記,方便後面求逆序對 b[a[i].i]=i; for(i=1;i<=n;i++) { update(b[i]);//一步一做 ans+=sum(b[i]-1); } printf("%lld\n",ans); n=read(); } return 0; }