關於逆序對的一種運用(樹狀陣列)

2021-08-28 17:57:31 字數 1422 閱讀 3868

主要題目:bzoj4430 2789

4430

題目大意:給定三個串,長度為n,求三個串中序列前後性質的字元對數。

發現直接求不好求,但是我們學過逆序對。已知總的對數是n(n-1),只要求出3個中前後不一樣的對數就好。

我們可以兩兩求出逆序對數,再除以2,用總對數減去就是答案了。

問題的關鍵在於對於兩兩序列求其中逆序的對數。

我們整理乙個序列ai,令ai為在第乙個串中位置為i的數再第二個串中的位置,那麼在兩串中若兩字元順序相同,那麼其在序列中一定是正序的,反之,就可以求出逆序的對數了。

#includeusing namespace std;

typedef long long ll;

const int maxn=2e5+10;

inline int read()

inline int lowbit(int x)

int cam[maxn][3],n,pos[maxn];

ll tree[maxn];

void add(int x)

}ll query(int x)

return res;

}ll work(int x,int y)

int main()

2789

題目大意:給定兩個串,求最少的交換次數使1串等於2串,交換只能相鄰的交換。

可以用反證法證明把1串中字元2串挪到最近的相同位置是最優的。(我不確定也不會證)

那麼我們考慮交換次數如何計算:

我們同樣求出如4030ai的乙個序列,那麼逆序對數就是最少的交換次數。在序列ai中,根據題目要求,我們要把它變成ai=i,這樣1、2串就相同了,考慮交換對於序列ai的改變,通過手算 我們可以發現交換就是序列ai相鄰位置的交換,那麼ai也只能相鄰交換,那麼每有乙個逆序對就意味著需要交換一次(感性理解一下),最後就把交換序列轉化成了逆序對數。

#includeusing namespace std;

typedef long long ll;

const int maxn=1e6+10;

char s1[maxn],s2[maxn];

int n,len[26],num[maxn],tree[maxn];

vectorsiz[26];

inline int lowbit(int x)

void add(int x)

}ll query(int x)

return ans;

}int main()

for(int i=1;i<=n;i++)

printf("%lld",ans);

return 0;

}

總結:我們發現對於字串之間的比較,我們可以構造類似序列a之類的東西來解決字串不同順序的問題,同時問題的轉化同樣重要。

逆序對的求法(樹狀陣列)

設a 1.n 是乙個包含n個不同數的陣列,如果在ia j 則 i,j 就稱為a中的乙個逆序對。求法有兩種,一種是歸併排序,一種是樹狀陣列。二者的時間複雜度都是o n logn 但樹狀陣列更加好寫。思路 開乙個樹狀陣列a記錄每乙個數出現的次數。倒序輸入,每輸入乙個數num就在a中加1,同時求一下從0到...

樹狀陣列求逆序對 演算法系列之 陣列中的逆序對

題目 劍指offer 01 題目描述在陣列中如果前乙個數字大於後乙個數字,則稱為這個數字組合組成乙個逆序對。輸入乙個陣列,求所有的逆序對的總數。如 陣列 則它的逆序對是 7,5 7,6 7,4 5,4 6,4 總共有五個。02 解法1 類似的題目,我們的第一反應都是,固定乙個數,如7,然後從後面的數...

蒜頭君的排序(樹狀陣列維護逆序對)

蒜頭君是乙個愛思考的好孩子,這一天他學習了氣泡排序,於是他就想,把乙個亂序排列通過氣泡排序排至公升序需要多少次交換,這當然難不倒他,於是他想來點刺激的,給定乙個 1 ldots n 1 n 的排列,每次從該排列中選擇乙個區間 l,r l,r 問使用氣泡排序將該區間排至公升序需要多少次交換操作。第一行...