二分的一些記錄

舉個例子,對於最大值最小的問題,二分求這個最小的最大值 ansans

這是一個題解的二分寫法,我發現好像大家都是這麼寫二分的 P3853 絕_塵的題解

 while(l<=r) {
        int mid=(l+r)>>1, k=0;
       	/*sentence code*/
       	
        if(k>t){
        	l=mid+1;
       	}
        else{
        	r=mid-1;
        	ans=mid;
        }
    }
    printf("%d",ans);
    
    return 0

本問題的二分的過程大約可以這麼形象的描述,對於遞增數列:

{\{a1a_{1}, a2a_{2}, a3a_{3} …, aia_{i}, ansans, aja_{j}, … ana_{n}}\}

ansans 及其以後的數值全部都符合題意,但是要求其中最小的值,也就是 ansans
對於此題,mid越大,k越小。使得 ktk\leq t 成立的mid是符合題意的。
而且要注意:即使 k==tk==t, 此時的mid也不一定就是ans

在這個代碼當中

  • k>tk>t 時,就相當於當前的 midmid 處於區間 [1,i][1, i]
  • ktk\leq t 時,就相當於當前的 midmid 處於區間 [j1,n][j-1, n], 也包含了最終結果 ansans

那麼就有個很顯然的問題:當mid恰好爲ans的時候,若 ktk\leq t ,那麼右邊界 r 將到達 ansans 的左側

此時會發生什麼?我們可以看到此while循環只有一個出口:l>rl>r, 那麼此時只要能跳出循環,就能輸出正確答案 ansans,否則不可能輸出正確答案 ansans

那麼什麼情況下, 本循環後能跳出呢?這裏注意兩點:

  1. r==lr == l, 則下一步跳出
  2. 如果此後得到的mid再也無法符合題意,則ans的值將不變,隨着 l 和 r 的緊縮,最終將到達1的情況,並跳出循環

不得不說,這個ans的設置相當巧妙,我tm以前怎麼沒發現這種寫法

當然,這裏是一定能找到結果的二分,還有的二分是可能查不到結果的,等下再寫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章