1. 程式人生 > >[Luogu 2816]宋榮子搭積木

[Luogu 2816]宋榮子搭積木

return 判斷 put algo 我們 輸出 == inpu sta

Description

saruka非常喜歡搭積木,他一共有n塊積木。而且saruka的積木很特殊,只能一塊塊的豎著摞,可以摞很多列。說過saruka的是特殊的積木了,這些積木都非常智能,第i塊積木有一個情緒值xi,當摞在這塊積木上的積木總數超過xi時,這塊積木就會很不高興,發誓以後不會再和saruka一起玩耍了。saruka這麽愛玩積木,肯定不會讓積木不高興的,但是saruka又希望每塊積木都被用上,並且摞的積木列數最少。你能來幫幫saruka嘛?

Input

第一行一個整數n,含義如題目描述所示

第二行有n個數xi,含義如題目描述所示

Output

輸出一個數字,代表最小的積木列數

Sample Input

3
0 0 10

Sample Output

2

HINT

1 <= n <= 5000

xi <= n

題解

題解都是從小到大排序...然後一個一個丟進去....

但是考場上想到的是二分...也過了...

我們將$x$排序從大到小,二分答案,將這$n$個數:第$i$個數放在$i$ $mod$ $mid$的堆上。邊遍歷邊判斷是否可行。

感覺應該也沒問題...也不會證(大概就是盡可能地利用了$x$吧...)

 1 //It is made by Awson on 2017.10.5
 2 #include <map>
 3
#include <set> 4 #include <cmath> 5 #include <ctime> 6 #include <queue> 7 #include <stack> 8 #include <vector> 9 #include <cstdio> 10 #include <string> 11 #include <cstdlib> 12 #include <cstring> 13 #include <iostream> 14
#include <algorithm> 15 #define LL long long 16 #define Max(a, b) ((a) > (b) ? (a) : (b)) 17 #define Min(a, b) ((a) < (b) ? (a) : (b)) 18 #define sqr(x) ((x)*(x)) 19 using namespace std; 20 const int N = 5000; 21 void read(int &x) { 22 char ch; bool flag = 0; 23 for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == -)) || 1); ch = getchar()); 24 for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar()); 25 x *= 1-2*flag; 26 } 27 28 int n, a[N+5]; 29 bool comp(const int &a, const int &b) { 30 return a > b; 31 } 32 33 bool judge(int mid) { 34 int rest[N+5]; 35 for (int i = 1; i <= mid; i++) 36 rest[i] = a[i]; 37 for (int i = mid+1; i <= n; i++) { 38 int t = i%mid; 39 if (!t) t = mid; 40 rest[t] = Min(rest[t]-1, a[i]); 41 if (rest[t] < 0) return false; 42 } 43 return true; 44 } 45 46 void work() { 47 read(n); 48 for (int i = 1; i <= n; i++) read(a[i]); 49 sort(a+1, a+n+1, comp); 50 int l = 1, r = n, ans = n; 51 while (l <= r) { 52 int mid = (l+r)>>1; 53 if (judge(mid)) ans = mid, r = mid-1; 54 else l = mid+1; 55 } 56 printf("%d\n", ans); 57 } 58 int main() { 59 work(); 60 return 0; 61 }

[Luogu 2816]宋榮子搭積木