對乙個序列給定兩種操作,交換兩個相鄰的數,求經過k
kk輪氣泡排序後逆序對個數。一輪氣泡排序指的是氣泡排序內層迴圈執行一遍。
可以發現,乙個數能進行交換,當且僅當前面沒有比它大的數。而且每輪前面比它大的數都會少1
11,因為前面有且僅有乙個最大的數到它的後面,其他較大且能交換的數一定遇到這個最大的數停止交換。所以乙個數在第幾輪被放在正確位置就看它前面數的個數。
再來研究交換。每次交換如果a
a< b,則逆序對加一,左邊的數比它大的數加一。如果a > ba>b a> b,則逆序對減一,右邊的數比它大的數減一。 再發現,想知道某一輪的逆序對個數那麼就是總的逆序對個數減去它前面每輪交換個數即可。每輪交換的個數就是n−n- n−放正確的個數。因為沒放正確的都會和乙個放正確大的做交換,所以就是求乙個字首和,要求字首和用樹狀陣列啊!把第乙個設為總的逆序對,後面的都是這一輪少的逆序對個數。交換一次就更新一下變化的數。因為我們要在求逆序對的同時求出前面比它大的個數,就剛好用樹狀陣列求很好。不知道怎麼求的,參考我寫的**:樹狀陣列。 細節問題:因為最開始我們在全部的逆序對進行修改,這樣後面的所有的逆序對個數都有了變化。那麼什麼時候變化要還原呢?過了交換之後的輪數就和原來是一樣的了。因為到了那個輪數把它們原來該交換的地方交換了要麼就換回去,要麼就原序列換成新序列,所以在該輪結束後要還原逆序對。 時間複雜度θ(m logn) \theta(m\log n) θ(mlogn) 。#include
using
namespace std;
const
int nn=
2e5+5;
int n,m,a[nn]
,b[nn]
,num[nn]
;long
long c[nn]
;int
lowbit
(int x)
void
add(
int x,
long
long sum)
}long
long
find
(int x)
return res;
}int
main()
memset
(c,0
,sizeof
(c))
;add(1
,res)
;int t=0;
for(
int i=
1;i<=n;i++
)for
(int i=
1;i<=m;i++
)else
}else
printf
("%lld\n"
,find
(x+1))
;}return0;
}
NOI Online 1 提高組 序列
luogu p6185 noi online 1 序列 將其轉化為圖論題。定義 u,v 為 a i 所代表的點 u v 為 b i 所代表的點 對於操作 2 將其視為一種權值搬運的操作,從 u 到 v 或者反過來轉移點權。那麼我們對 u,v 和 u v 連一條無向邊,顯然對於乙個連通塊內的所有點都可...
NOI Online 1 提高組 氣泡排序
這個題很繞,記數字i前面有cns i 個數字比他大,逆序對個數就是sigmi cns i 反轉k次就是讓cns i k i 1 i n 而且cns i 不能有負數 利用兩個線段樹維護一下,就是有點繞。include include include include includeusing names...
NOI Online 1 入門組 魔法
全網都是矩陣快速冪,我只會倍增dp 其實這題與 acwing 345.牛站 還是比較像的,那題可以矩陣快速冪 倍增,這題也行。先 floyd 預處理兩點之間不用魔法最短距離 d 複雜度 o n 3 然後預處理兩點之間至多用乙個魔法的最短距離 w 初始為 w d 列舉 i,j 和一條邊 u,v,t w...