1. 程式人生 > 其它 >Acwing 社交距離 分類討論+貪心

Acwing 社交距離 分類討論+貪心

一種新型疾病,COWVID-19,開始在全世界的奶牛之間傳播。

Farmer John 正在採取儘可能多的預防措施來防止他的牛群被感染。

Farmer John 的牛棚是一個狹長的建築物,有一排共 N 個牛欄。

有些牛欄裡目前有奶牛,有些目前空著。

得知“社交距離”的重要性,Farmer John 希望使得 D 儘可能大,其中 D 為最近的兩個有奶牛的牛欄的距離。

例如,如果牛欄 3 和 8是最近的有奶牛的牛欄,那麼D=5。

最近兩頭奶牛新來到 Farmer John 的牛群,他需要決定將她們分配到哪兩個之前空著的牛欄。

請求出他如何放置這兩頭新來的奶牛,使得 D 仍然儘可能大。

Farmer John 不能移動任何已有的奶牛;他只想要給新來的奶牛分配牛欄。

輸入格式

輸入的第一行包含 N。

下一行包含一個長為 N 的字串,由0 和 1 組成,描述牛棚裡的牛欄。

0 表示空著的牛欄,1 表示有奶牛的牛欄。

字串中包含至少兩個 0,所以有足夠的空間安置兩頭新來的奶牛。

輸出格式

輸出 Farmer John 以最優方案在加入兩頭新來的奶牛後可以達到的最大 D 值(最近的有奶牛的牛欄之間的距離)。

2N10^5

分析題幹:我們先淺淺地分析一下題幹,這道題地意思就是我們往標號是0的圍欄中放入兩頭奶牛,然後我要讓兩頭奶牛之間的座標差D越大越好;

一開始我是用了一個比較笨的思路,我考慮兩頭奶牛是不是要相鄰的放,但這樣的話考慮到出事的奶牛會有很多種情況,可能在頭部,可能在中間有一個,可能一個都沒有就需要分太多類了;

所以後買你在看題解的時候遇到的這個方法很好,我們可以先通過初始化牛欄陣列來得到當前的D,已知加入兩頭奶牛之後,D不會變大,所以我們可以二分的搜尋答案,我們令l = 1 , r = D,然後取mid,我們看噹噹前最大的D取到mid時可不可以插入兩頭牛;

所以我就寫了一個check函式,我們把每一個已經放了牛的位置放在一個數組裡面,我們從第一個數開始看,如果p(當前的位置)滿足,p + mid + mid <= a[i],也就是說我在p後面mid的地方觀察能不能放一頭牛,也就是會不會和後面一個位置的牛的距離小於mid,如果行就插入並將p往後移動mid位置,重複操作直到不能插入,然後我就將p移動到a[i]上,以此類推;

值得注意的是,跳出迴圈後,p可能在最後一個已經有牛的位置上,他後面全是0,我也要向上面一樣去做判斷,最後觀察我在保證D = mid的情況下能不能插入兩頭牛以上,能得話我就讓ans = mid,然後繼續二分直到邊界跳出!

這樣二分答案是非常常見的!

 

程式碼:

#include<bits/stdc++.h>
#define maxn 100010

using namespace std;
int n,m,ans = 0;
char str[maxn];
int a[maxn];

bool check(int x){
int p = 1-x , cnt = 0;
for(int i = 1;i<=m;i++){
while(p+x+x<=a[i]) p+=x, cnt++;
p = a[i];
}
while(p+x<=n) p+=x, cnt++;
return cnt>=2;
}

int main()
{
cin >> n;
cin >> str+1;
for(int i = 1;i<=n;i++)
if(str[i] == '1' ) a[++m] = i;
int l = 1 ,r = n;
for(int i=1; i<m; i++) r=min(r,a[i+1]-a[i]);
while(l<=r)
{
int mid = l+r >> 1;
if(check(mid)){
ans = mid;
l = mid+1;
}
else r = mid-1;
}
cout << ans;
return 0;
}