求逆序對的題目,可以用暴力、樹狀數組來實現。
1。暴力法:O(n^2)對於1000的規模完全可以做,直接找第i個元素之後有多少個比其小的元素即可。
代碼:
#include <iostream><br />#include <cstdio><br />#include <cstring><br />#include <cstdlib></p><p>using namespace std;</p><p>int main()<br />{<br />int t,n,cnt=0;<br />int a[1005];<br />int ret;</p><p>scanf("%d",&t);<br />while(t--)<br />{<br />cnt++;<br />scanf("%d",&n);<br />for(int i=0;i<n;i++)<br />scanf("%d",&a[i]);</p><p>ret=0;<br />for(int i=0;i<n;i++)<br />for(int j=i+1;j<n;j++)<br />if(a[i]>a[j])<br />ret++;<br />printf("Scenario #%d:/n",cnt);<br />printf("%d/n",ret);<br />if(t)<br />printf("/n");<br />}</p><p>return 0;<br />}<br />
運用樹狀數組,每次維護小於K的數的個數,從後往前求和,時間複雜度是O(nlogn)的,注意數的範圍很大,是2000000,這樣用這種方法反而不快。
代碼:
#include <iostream><br />#include <cstdio><br />#include <cstring><br />#include <cstdlib></p><p>using namespace std;</p><p>const int MAX=2000100;<br />int seg[MAX],a[1100];</p><p>void add(int k)<br />{<br />while(k<MAX)<br />{<br />seg[k]++;<br />k+=k&-k;<br />}<br />}</p><p>int sum(int k)<br />{<br />int ret=0;</p><p>while(k)<br />{<br />ret+=seg[k];<br />k-=k&-k;<br />}</p><p>return ret;<br />}</p><p>int main()<br />{<br />int t,n,cnt=0;<br />int ret;</p><p>scanf("%d",&t);<br />while(t--)<br />{<br />cnt++;<br />scanf("%d",&n);<br />for(int i=0;i<n;i++)<br />{<br />scanf("%d",&a[i]);<br />a[i]+=1000001;<br />}</p><p>ret=0;<br />memset(seg,0,sizeof(seg));<br />for(int i=n-1;i>=0;i--)<br />{<br />ret+=sum(a[i]-1);<br />add(a[i]);<br />}<br />printf("Scenario #%d:/n",cnt);<br />printf("%d/n",ret);<br />if(t)<br />printf("/n");<br />}</p><p>return 0;<br />}<br />
我也嘗試寫了一下,但是逾時了,由於數的範圍大,而線段樹的初始化時間效率低,線段樹的初始化時間是O(nlogn)而樹狀數組的初始化時間是O(n)的,這裡差距很大。
總結:能用樹狀數組代替線段樹的,盡量代替,不僅代碼量小,而且效率高。