二分 折半 筆記

2021-10-02 08:01:49 字數 3431 閱讀 5821

菜雞今天又開始了乙個新的演算法,廢話不多說,開始筆記。二分查詢是乙個十分常用的演算法,適用於對帶有單調性的資料進行處理或查詢。大多數題目可能沒那麼顯示,需要自己來找這個單調性在哪,所以這就是乙個重點,具體的用法和**很簡單,就那麼幾行,但是對於折半的條件卻需要有嚴格的要求。

[牛客]完全平方數

就如這個題目:多次查詢[l,r]範圍內的完全平方數個數。這樣的題目通常需要經過預處理。因為資料量看起來比較大1e9,你也沒法預處理哪個數是不是完全平方數。但是,完全平方數嘛,就必然是乙個數的平方,那我們可以存一下,每乙個數對應的完全平方數是誰。如:1->1,2->4,這樣以此類推,正好我們的下標的平方就是我們儲存的資料。而且我們也正好可以知道從1到這個數,已經有多少個完全平方數了,有點字首和的感覺,這樣,我們每遇到乙個區間就可以直接二分查詢兩個端點的位置,然後做差,就正好是這個範圍內所求性質的數的個數了。這裡要注意一下,最好是要在二分查詢的時候用左閉右開,這樣你後面那個查到的永遠是比你右端點大的位置,用這個直接減掉左端點就是其中數的個數了。

總結一下,我們的思想就是,大資料我們存不下,我們可以把某些具有該特性的數預處理先存在陣列裡面,借助陣列下表當做字首和,來相當於把乙個大的區間進行了離散化,在進行二分查詢。

#include

#include

#include

using

namespace std;

long number[

100010];

intmain()

return0;

}

**很簡單的,對吧~

01分數規劃的題目可以借助二分進行近似求解。至於什麼是01分數規劃,在這裡稍微簡單做下筆記,當然可以問度娘。

0/1分數規劃模型是指,有一些二元組(si,pi),從中選取一些二元組,使得∑si / ∑pi最大(最小)。

這種題一類通用的解法就是,我們假設x = ∑si / ∑pi的最大(小)值,那麼就有x * ∑pi = ∑si ,即∑si - x * ∑pi= 0。也就是說,當某乙個值x滿足上述式子的時候,它就是要求的值。所以我們直接二分答案,當上述式子》0,說明答案小了,<0則說明答案大了,這樣計算即可。

[牛客]wyh的物品

#include

#include

#include

#include

using

namespace std;

const

int maxn =

1e5+5;

const

double eps =

0.001

;double v[maxn]

, w[maxn]

, x[maxn]

;int

main()

double mid, sum =0;

while

(fabs

(r-l)

> eps)

printf

("%.2lf\n"

, mid);}

return0;

}

[牛客]andy的樹被砍了

這種一般就比較簡單吧,一般就是字首和,畢竟是字首和,也沒有負數,單調性很明顯,然後用二分的話可能**就會簡化一點,時間複雜度低一點。感覺可用可不用。我看好像都沒用二分就過了。

#include

#include

#include

using

namespace std;

const

int maxn =

1e5+5;

long

long c[maxn]

;int h[maxn]

;int

main()

cout << endl;

return0;

}

emmm,比暴力的**更簡潔一點。

有些題目要特別巧妙的使用字首和,可以大量的減少時間複雜度:[牛客]transform,而且確定邊界的時候一定要好好想想,要不然就一直錯。

#include

#include

using

namespace std;

const

int maxn =

5e5+5;

int n;

long

long t;

int x[maxn]

;long

long a[maxn]

, _sum[maxn]

, _cost[maxn]

;inline

long

long

getrightcost

(int l,

int r)

inline

long

long

getleftcost

(int l,

int r)

bool

check

(long

long _try)

l = r = mid = n;

while

(true

)return

false;}

intmain()

r = _sum[n]

;while

(l <= r)

printf

("%lld\n"

, r)

;return0;

}

一般我們習慣性的對所求答案進行二分,比如:[牛客]接機

一般的都是乙個模板:

while

(l < r)

重點在於根據題目怎麼寫這個check函式,還有就是對於邊界的判斷,要想好,哪乙個是可行解,應該保留哪乙個邊界。

#include

#include

using

namespace std;

const

int maxn =

1e5+5;

int _time[maxn]

;inline

bool

check

(int n,

int m,

int c,

int mid)

return cnt <= m;

}int

main()

printf

("%d\n"

, r)

;return0;

}

還有一種比較不容易出錯的寫法:

while

(l <= r)

這樣把最後求得的可行解儲存在乙個變數裡面,就可以不用邊界是否正確,最後的解一定是可行的。

剛開始,沒做多少題目,日後再更~

二分 折半 查詢

折半查詢 又叫二分查詢,採用分治思想,適用於不經常變動且查詢頻繁的表 演算法思想 將n個元素 假設n個元素公升序 分為大致相同的兩部分,取data n 2 與目標元素m比較 若data n 2 m return n 2 若data n 2 m 則我們只要在data的左半部分繼續查詢 若data n ...

二分 折半 查詢

二分查詢 請對乙個有序陣列進行二分查詢 輸入乙個數看看該陣列是否存在此數,並且求出下 標,如果沒有就提示 沒有這個數 二分查詢演算法的思路 二分 折半 查詢條件 有序陣列。public class binarysearch 不考慮有重複元素的查詢。int index solutionsearch a...

二分折半排序

板子 插入後,每次與中間值相比較,再與左半部分中間值比較,再與右半部份中間值比較,直到找到它自己的位置,待排序資料 2,1,6,7,4 資料部分 原文 取第乙個元素作為有序表,剩餘的元素作為無序表 其中有序表 2 無序表 1,6,7,4 第一次比較,從無序表中取出第乙個數 1,與中間值2比較,1 2...