一年一度的「跳石頭」比賽又要開始了!
這項比賽將在一條筆直的河道中進行,河道中分布著一些巨大岩石。組委會已經選擇好了兩塊岩石作為比賽起點和終點。在起點和終點之間,有 nnn 塊岩石(不含起點和終點的岩石)。在比賽過程中,選手們將從起點出發,每一步跳向相鄰的岩石,直至到達終點。
為了提高比賽難度,組委會計畫移走一些岩石,使得選手們在比賽過程中的最短跳躍距離盡可能長。由於預算限制,組委會至多從起點和終點之間移走 mmm 塊岩石(不能移走起點和終點的岩石)。
輸入格式:
第一行包含三個整數 l,n,ml,n,ml,n,m,分別表示起點到終點的距離,起點和終點之間的岩石數,以及組委會至多移走的岩石數。保證 l≥1l \geq 1l≥1 且 n≥m≥0n \geq m \geq 0n≥m≥0。
接下來 nnn 行,每行乙個整數,第 iii 行的整數 di(0di(0輸出格式:
乙個整數,即最短跳躍距離的最大值。
輸入樣例#1:複製
25 5 2 2111417
21
輸出樣例#1:複製
4
輸入輸出樣例 1 說明:將與起點距離為 222和 141414 的兩個岩石移走後,最短的跳躍距離為 444(從與起點距離 171717 的岩石跳到距離 212121 的岩石,或者從距離 212121 的岩石跳到終點)。
另:對於 20%20\%20%的資料,0≤m≤n≤100 ≤ m ≤ n ≤ 100≤m≤n≤10。
對於50%50\%50%的資料,0≤m≤n≤1000 ≤ m ≤ n ≤ 1000≤m≤n≤100。
對於 100%100\%100%的資料,0≤m≤n≤50,000,1≤l≤1,000,000,0000 ≤ m ≤ n ≤ 50,000,1 ≤ l ≤ 1,000,000,0000≤m≤n≤50,000,1≤l≤1,000,000,000
附上0分**
#include
#define for(i,l,r) for(int i=l;i<=r;i++)
#define inf 0x7f7f
using namespace std;
long long ll,n,m,a[inf],mid,ans,l,r;
//首先是可行,其次考慮最優
bool check(int x)
a[n+1]=ll;
l=1,r=ll;
while(l<=r)
else r=mid-1;
}cout<
附上滿分**
#include
#define for(i,l,r) for(int i=l;i<=r;i++)
#define inf 0x7f7f7f
using namespace std;
long long ll,n,m,a[inf],mid,ans,l,r;
//首先是可行,其次考慮最優
bool check(int x)
a[n+1]=ll;
l=1,r=ll;
while(l<=r)
else r=mid-1;//這些可以根據自己理解寫
}cout<
看看有什麼不同
是不是很坑
好了回歸主題
二分就是乙個從可行性問題到最優性問題
關鍵是看她可行解是在什麼範圍,可行解向最優解過度是左移還是右移
二分答案應該是在乙個單調閉區間上進行的。也就是說,二分答案最後得到的答案應該是乙個確定值,而不是像搜尋那樣會出現多解。二分一般用來解決最優解問題。剛才我們說單調性,那麼這個單調性應該體現在**呢?
可以這樣想,在乙個區間上,有很多數,這些數可能是我們這些問題的解,換句話說,這裡有很多不合法的解,也有很多合法的解。我們只考慮合法解,並稱之為可行解。考慮所有可行解,我們肯定是要從這些可行解中找到乙個最好的作為我們的答案, 這個答案我們稱之為最優解。
最優解一定可行,但可行解不一定最優。我們假設整個序列具有單調性,且乙個數x為可行解,那麼一般的,所有的x'(x'y)都是非法解。
那麼什麼時候適用二分答案呢?注意到題面:使得選手們在比賽過程中的最短跳躍距離盡可能長。如果題目規定了有「最大值最小」或者「最小值最大」的東西,那麼這個東西應該就滿足二分答案的有界性(顯然)和單調性(能看出來)。
那就好辦了。我們二分跳躍距離,然後把這個跳躍距離「認為」是最短的跳躍距離,然後去以這個距離為標準移石頭。使用乙個judge判斷這個解是不是可行解。如果這個解是可行解,那麼有可能會有比這更優的解,那麼我們就去它的右邊二分。為什麼去右邊?答案是,這個區間是遞增的 ,而我們求的是最短跳躍距離的最大值,顯然再右邊的值肯定比左邊大,那麼我們就有可能找到比這更優的解,直到找不到,那麼最後找到的解就有理由認為是區間內最優解。反過來,如果二分到的這個解是乙個非法解,我們就不可能再去右邊找了。因為性質,右邊的解一定全都是非法解。那麼我們就應該去左邊找解。整個過程看起來很像遞迴,實際上,這個過程可以遞迴寫, 也可以寫成非遞迴形式,我個人比較喜歡使用非遞迴形式。
下乙個問題,這個judge怎麼實現呢?judge函式每個題有每個題的寫法,但大體上的思想應該都是一樣的——想辦法檢測這個解是不是合法。拿這個題來說,我們去判斷如果以這個距離為最短跳躍距離需要移走多少塊石頭,先不必考慮限制移走多少塊,等全部拿完再把拿走的數量和限制進行比對,如果超出限制,那麼這就是乙個非法解,反之就是乙個合法解,很好理解吧。
可以去模擬這個跳石頭的過程。開始你在i(i=0)位置,我在跳下一步的時候去判斷我這個當前跳躍的距離,如果這個跳躍距離比二分出來的mid小,那這就是乙個不合法的石頭,應該移走。為什麼?我們二分的是最短跳躍距離,已經是最短了,如果跳躍距離比最短更短豈不是顯然不合法,是這樣的吧。移走之後要怎麼做?先把計數器加上1,再考慮向前跳啊。去看移走之後的下一塊石頭,再次判斷跳過去的距離,如果這次的跳躍距離比最短的長,那麼這樣跳是完全可以的,我們就跳過去,繼續判斷,如果跳過去的距離不合法就再拿走,這樣不斷進行這個操作,直到i = n+1,為啥是n+1?河中間有n塊石頭,顯然終點在n+1處。(這裡千萬要注意不要把n認為是終點,實際上從n還要跳一步才能到終點)。
模擬完這個過程,我們檢視計數器的值,這個值代表的含義是我們以mid作為答案需要移走的石頭數量,然後判斷這個數量 是不是超了就行。如果超了就返回false,不超就返回true。//以上皆為**
牛舍#include
#define for(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
int n,m,a[101010],r,l,mid;
bool check(int x)
return cow==m?1:0;
}int main()
sort(a+1,a+n+1);
l=0,r=a[n]-a[1];
doelse
r=mid-1;
}while(l<=r);
cout陶陶是個貪玩的孩子,他在地上丟了a個瓶蓋,為了簡化問題,我們可以當作這a個瓶蓋丟在一條直線上,現在他想從這些瓶蓋裡找出b個,使得距離最近的2個距離最大,他想知道,最大可以到多少呢?
輸入格式:
第一行,兩個整數,a,b。(b<=a<=100000)
第二行,a個整數,分別為這a個瓶蓋座標。
輸出格式:
僅乙個整數,為所求答案。
輸入樣例#1:複製
5 31 2 3 4 5
輸出樣例#1:複製
2
限時3秒
0分**
#include
#define for(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
long long n,m,a[101010],r,l,mid,ans,ct=1,now=1;
bool check(int x)
return ct>=m?1:0;
}int main()
sort(a+1,a+n+1);
l=0,r=a[n]-a[1];
while(l<=r)
else
r=mid-1;
}cout<100分**
#include
#define for(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
long long n,m,a[101010],r,l,mid,ans,ct=1,now=1;
bool check(int x)
}return ct>=m?1:0;
}int main()
sort(a+1,a+n+1);
l=0,r=a[n]-a[1];
while(l<=r)
else
r=mid-1;
}cout《真的就是乙個括號讓我調了半個小時啊啊,差點就放棄了
二分查詢 從酒桌遊戲看二分查詢演算法
給前端食堂加星標,吃好每一頓 觀感度 口味 孜然牛肉 本文已收錄在githubgithub.com geekhyt,感謝star。酒桌上曾經玩過這樣乙個小遊戲,遊戲規則是 主持人每次隨機從 1 1000 中選擇乙個數字,比如是 171。只有主持人自己知道並事先寫在紙條上留存,然後分別讓大家來猜,能夠...
(c語言)最大子列和問題(非二分查詢和二分查詢)
給定k個整數組成的序列,連續子列 被定義為,其中 1 i j k。最大子列和 則被定義為所有連續子列元素的和中最大者。例如給定序列,其連續子列有最大的和20。現要求你編寫程式,計算給定整數序列的最大子列和。本題旨在測試各種不同的演算法在各種資料情況下的表現。各組測試資料特點如下 資料1 與樣例等價,...
二分查詢的越界和死迴圈問題
個人看來,二分查詢有兩個易錯點,那就是 越界 和 死迴圈 這裡拿左閉右閉和左閉右開來說,1 左閉右開 int binarysearch seqlist s,datatype x else if s array mid x else 這裡int left 0,right s size while le...