火車站臺連鎖店(題解)
阿新 • • 發佈:2020-08-24
火車站臺連鎖店 首先這道題是一道二分經典題(很難很難)
我們為什麼要用二分呢,因為每一次選擇數字,無論偏大還是偏小,都可以讓剩下的選擇範圍縮小一半
我們先來看看題目及範圍
先來看看題目的意思:
大概的意思是我們要讓這n個站臺中的m個站臺裡,讓每兩個站臺間的距離都儘可能的大。
因為這道題要求輸出最大的最近距離,所以我們就來二分距離。
但是我們需要一個輔助函式bool來計算最短距離能開設多少家店。
bool ok(int x) { int tot = 1; int last = 1; for(int i = 1; i <= n; i++) {while(a[i]-a[last] < x) { i++; if(i > n) { return tot >= m; } } last = i; tot++; } return tot >= m; }
我們用tot和last這兩個臨時變數來儲存我們的資料(個人喜好)
怎麼實現查詢?
首先確定初始範圍
因為我們要把最短距離進行二分查詢,所以我們需要一個最初始的left以及right的值。可以肯定的是,這個最短距離L一定在1~最大座標-最小座標。
通過幾次查詢,如果我們不停下來的話,left,right,mid三個值都不會再發生變化
因為我們的二分寫發是
while(left<right)
因為我們二分的寫法是每次left和right其一等於mid,但當它們其中一個和mid相等的時候,這就會成為一個死迴圈
所以我們就需要改成
while(right - left > 1)
完整程式碼如下
#include <bits/stdc++.h> using namespace std; int n, m; int a[100010]; bool ok(int x) { int tot = 1; intlast = 1; for(int i = 1; i <= n; i++) { while(a[i]-a[last] < x) { i++; if(i > n) { return tot >= m; } } last = i; tot++; } return tot >= m; } int main() { cin >> n >> m; for(int i = 1; i <= n; i++) { cin >> a[i]; } sort(a+1,a+1+n); int l = 0, r = a[n]-a[1]; while(r-l>1) { int mid=(l+r)/2; if(ok(mid)) { l = mid; } else { r = mid; } } if(!ok(r)) { r = l; } cout << r; return 0; }
順便一說:
老大在天上一定也有籃球吧,今天是你的紀念日,一路走好。