这个问题我一开始没做出来,参考了https://blog.csdn.net/a1097304791/article/details/87874948#t3 和 https://www.cnblogs.com/albert67/p/10414426.html|
之后才会做,我就权当记录一下,并且再理一下思路吧:
收获:1:二分查找在数据量较大的有序数据中的优化作用;
2:思维题模摸门道
本题思路:枚举天数判断那一天能喝完且最少,可用二分查找优化。
思维上有问题的可能是:咖啡因在一天多次时的损耗-1、-2等不管是先喝咖啡因多得还是咖啡因少的都是一样的,多的-1和少的-1是一样的;所以不管你是正序排列还是逆序排列答案都是一样的;
我加了些注释:
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 210000;
int n, m, arr[maxn];
bool cmp(int a, int b) { return a > b; }
bool check(int x)
{
LL sum = 0;
for (int i = 1, t = 0; i <= n; i++) {
sum += ( arr[i] - t );
if (i%x == 0) t++; //这里用得很好, 表示每组为x天
if (arr[i] <= t) break; //剪枝:i再增加,arr[i]也不会增加了,可以加速了
}
/*int k = 1;
int t = 0;
for (int i = 1; i <= n; ++i)
{
if (k == x)break;
if (arr[i] - t <= 0)
{
k++;
t = 1;
--i;
}
sum += arr[i] - t;
t++;
}*/
return sum >= m;
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> arr[i];
sort(arr + 1, arr + 1 + n, cmp);
int l = 1, r = n + 1, ans = 1 << 30;//有可能完不成
/*
二分查找的作用在于快速找到最少的可以完成的天数
*/
while (l < r) {
int mid = ( l + r ) / 2;
if (check(mid))
r = mid, ans = min(ans, mid); //能完成,所以看看能不能天数再少点
else
l = mid + 1; //完不成,所以天数加一天
}
if (ans != 1 << 30) cout << ans << endl;
else cout << "-1" << endl;
return 0;
}