题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=1816
题意:有$N$堆牌,第$i$堆牌有$c_i$张牌,还有$M$张$joker$,每一次可以从$N$堆牌中任选一张组成一副牌,或者在任意$N - 1$堆中选择$1$张牌加上一张$joker$组成一副牌,问最多能组成多少副牌。$N \leq 50 , m , c_i \leq 5 \times 10^8$
清流题qwq
每一次的消除一定是在牌最少的一堆使用$joker$,$joker$就等效于这一堆中额外的一张牌。所以先考虑加完$joker$一起减的情况,也就是先把第一少的堆加$joker$直至与第二少的堆牌量相同,然后在前两少的堆中同时加$joker$直至前三堆牌量相同,这么一直做下去,直到$joker$不够或者$N$堆加成一样高,把剩下的$joker$平摊在每一堆上就是最优策略。
然而这样子会有一个问题:一次取牌只能取出一张$joker$,但我们的方案中很有可能一次取出多张$joker$。我们不妨这样考虑:在排序之后,前两堆牌每一次至少会取出一张牌,前三堆牌每一次至少会取出两张牌,以此类推,我们可以得到一个取牌的上界,将这个上界与上面的答案取$min$即可
所以请无视我的高精$QuQ$
1 #include<bits/stdc++.h>
2 #define ll long long
3 using namespace std;
4
5 const int MOD = 1e9;
6 inline ll read(){
7 ll a = 0;
8 char c = getchar();
9 while(!isdigit(c))
10 c = getchar();
11 while(isdigit(c)){
12 a = (a << 3) + (a << 1) + (c ^ '0');
13 c = getchar();
14 }
15 return a;
16 }
17
18 struct Bignum{
19 int num[3];
20 Bignum(ll x){
21 int i = 0;
22 while(i <= 2){
23 num[i++] = x % MOD;
24 x /= MOD;
25 }
26 }
27 Bignum operator +=(ll x){
28 int i = 0;
29 while(x){
30 num[i] += x % MOD;
31 if(num[i] > MOD){
32 num[i + 1]++;
33 num[i] -= MOD;
34 }
35 x /= MOD;
36 i++;
37 }
38 return *this;
39 }
40
41 ll operator /(int x){
42 ll sum = 0 , ans = 0;
43 for(int i = 2 ; i >= 0 ; i--){
44 sum = sum * MOD + num[i];
45 ans = ans * MOD + sum / x;
46 sum %= x;
47 }
48 return ans;
49 }
50 };
51 ll num[51];
52
53 int main(){
54 freopen("easy.in" , "r" , stdin);
55 freopen("easy.out" , "w" , stdout);
56 int N;
57 ll M;
58 N = read();
59 M = read();
60 for(int i = 1 ; i <= N ; i++)
61 num[i] = read();
62 sort(num + 1 , num + N + 1);
63 int dir = 1;
64 ll minN = 1e18 + 1;
65 Bignum sum = num[dir];
66 while(dir < N && num[dir + 1] - num[dir] <= M / dir){
67 M -= (num[dir + 1] - num[dir]) * dir;
68 sum += num[dir + 1];
69 minN = min(minN , sum / dir);
70 dir++;
71 }
72 cout << min(minN , num[dir] + M / dir) << endl;
73 return 0;
74 }