1. 程式人生 > >BZOJ-1816: [Cqoi2010]撲克牌(二分答案)

BZOJ-1816: [Cqoi2010]撲克牌(二分答案)

ont printf span put esc 輸出 i++ enter fine

1816: [Cqoi2010]撲克牌

Time Limit: 10 Sec Memory Limit: 64 MB
Submit: 2640 Solved: 1046
[Submit][Status][Discuss]

Description

你有n種牌,第i種牌的數目為ci。另外有一種特殊的牌:joker,它的數目是m。你可以用每種牌各一張來組成一套牌,也可以用一張joker和除了某一種牌以外的其他牌各一張組成1套牌。比如,當n=3時,一共有4種合法的套牌:{1,2,3}, {J,2,3}, {1,J,3}, {1,2,J}。 給出n, m和ci,你的任務是組成盡量多的套牌。每張牌最多只能用在一副套牌裏(可以有牌不使用)。

Input

第一行包含兩個整數n, m,即牌的種數和joker的個數。第二行包含n個整數ci,即每種牌的張數。

Output

輸出僅一個整數,即最多組成的套牌數目。

Sample Input

3 4
1 2 3

Sample Output

3

樣例解釋
輸入數據表明:一共有1個1,2個2,3個3,4個joker。最多可以組成三副套牌:{1,J,3}, {J,2,3}, {J,2,3},joker還剩一個,其余牌全部用完。

數據範圍
50%的數據滿足:2 < = n < = 5, 0 < = m < = 10^ 6, 0< = ci < = 200
100%的數據滿足:2 < = n < = 50, 0 < = m, ci < = 500,000,000。
首先,我們不難發現有二分性。 我們二分一下答案,枚舉一下1~n哪些牌是不夠的,用joker來填,這個不難理解 但是本人卻不知道如何解釋怎樣讓每套牌joker只有一張 後來在zhz的幫助下終於理解了 我們可以把答案想象成一條線,一段線上分割成兩端,一段表示需要用joker,一段表示原先有的,我們只要保證需要用joker的牌小於等於min(joker數,當前二分的數)(為每套牌最多只能有一張joker)就可以了。 具體的可以自己畫個圖模擬一下 技術分享圖片
 1 #include<bits/stdc++.h>
 2 #define N 55
 3 using namespace std;
4 int n,m; 5 int a[N]; 6 bool check(int x){ 7 int s=min(x,m); 8 for (int i=1;i<=n;i++){ 9 if (a[i]<x) s-=(x-a[i]); 10 if (s<0) return false; 11 } 12 return true; 13 } 14 int main(){ 15 scanf("%d%d",&n,&m); 16 for (int i=1;i<=n;i++) 17 scanf("%d",&a[i]); 18 int l=1,r=1e9,ans; 19 while (l<=r){ 20 int mid=(l+r)>>1; 21 if (check(mid)){ 22 ans=mid; 23 l=mid+1; 24 } else r=mid-1; 25 } 26 printf("%d\n",ans); 27 return 0; 28 }
View Code

BZOJ-1816: [Cqoi2010]撲克牌(二分答案)