1. 程式人生 > 實用技巧 >雙指標&整數二分思路總結

雙指標&整數二分思路總結

近日小夥伴說得口訣

圖難在建模、貪心難在證明、資料結構難在實現、搜尋難在剪支、動態規劃難在狀態表示
二分雙指標難在單調性(所以說見到陣列,能排序就排序,因為排序是二分和雙指標的介面)

正題

本文將介紹雙指標&二分的思路。先由具體題目,在抽象出一般方法。下面先上題目。

Pair of Topics

題目連結:https://codeforces.com/contest/1324/problem/D
題意:

The next lecture in a high school requires two topics to be discussed. The i-th topic is interesting by ai units for the teacher and by bi units for the students.

The pair of topics i and j (i<j) is called good if ai+aj>bi+bj (i.e. it is more interesting for the teacher).

Your task is to find the number of good pairs of topics.

Input
The first line of the input contains one integer n (2≤n≤2⋅105) — the number of topics.

The second line of the input contains n integers a1,a2,…,an (1≤ai≤109), where ai is the interestingness of the i-th topic for the teacher.

The third line of the input contains n integers b1,b2,…,bn (1≤bi≤109), where bi is the interestingness of the i-th topic for the students.

Output
Print one integer — the number of good pairs of topic.
input
5
4 8 2 6 2
4 5 4 1 3

output
7

input
4
1 3 2 4
1 3 2 4
output
0

閱讀理解:先給出兩個陣列:a,b。兩陣列長度相同,a中元素為教師對第index(陣列下標)個tipic的感興趣程度,b則是學生。現在要求出good topic的pair數。就是一對topic瞞住ai + aj > bi + bj ,i和j就是一對好topic。求有多少對這樣的topic。

思路:
法1:暴力,不重不漏地列舉每一對tipic。顯然這個方法會TLE,因為n=2*1e5,O(n^2)的時間複雜度。
法2:1)、變形判斷公式 2)、構造新判斷條件 3)、排序,利用雙指標
法3:與法2前兩步相同,第3步也是排序,只不過後面用的是整數二分。

coding

法2:公式咋變形? ai + aj > bi + bj --> (ai - bi) + (aj - bj ) > 0 --> 也就是 ci + cj > 0.
問題就變成c陣列中,兩個數加起來大於0,的個數。這時候,排序,利用單調,最快找到剛好滿足條件的最後一個點。然後累加答案即可。
ci + cj > 0 用雙指標分析,關鍵是看l,r指標的方向l,r。列舉l端點,即系l端點單調增加(index不斷增加),ci =- -cj,左邊變大,右邊也要變大,因為有負號,所以只能變小。因此l,r是對向的
初始化l= 0 ,r = n-1。r指標不用回溯,因為...之前的l是肯定包含l+1的。快就快在這裡。
程式碼如下:

#include <bits/stdc++.h> 

using namespace std;
const int N  = 200010;
typedef long long LL;
int a[N],n;
int main(){
	#ifndef  ONLINE_JUDGE
		freopen("topics.txt","r",stdin);
	#endif
	cin >> n;
	for(int i = 0 ; i < n; i++) cin >> a[i];
	
	for(int i = 0; i < n; i++){
		int t; cin >> t;
		a[i] = a[i] - t;
	}
	sort(a,a+n);
	int l  , r = n-1;
	LL ans = 0;
	//列舉l
	for(int i = 0 ; i < n; i++) {
		l = i;
		while(r >=0 && a[l] + a[r] > 0) r--;
		ans += n - max(r,l) - 1;
	}
	cout << ans <<endl;
} 
今天先更新到這 下篇部落格在更新第3個方法,二分。