BZOJ1816 CQOI2010 扑克牌 贪心

题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=1816

题意:有$N$堆牌,第$i$堆牌有$a_i$张牌,还有$M$张$joker$,每一次可以从$N$堆牌中任选一张组成一副牌,或者在任意$N - 1$堆中选择$1$张牌加上一张$joker$组成一副牌,问最多能组成多少副牌。


清流题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 }

猜你喜欢

转载自www.cnblogs.com/Itst/p/9755197.html