主要題目: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 問使用氣泡排序將該區間排至公升序需要多少次交換操作。第一行...