题目描述:
奶牛bessie有n根蜡烛,第i根蜡烛的长度是h[i]。bessie最近刚上完小学,只会加减法。它想知道它的n根蜡烛最多能用多少个晚上。由于bessie比较胆小,因此它每天晚上需要点燃c根蜡烛。每根被点燃的蜡烛,它燃烧一个晚上会使得它的长度减少1。一旦蜡烛的长度变成0,那么该根蜡烛就用完了。如果第i个晚上bessie发现蜡烛不够用了,那么bessie最多就只能用i-1个晚上。
Bessie想知道,它该如何选择每个晚上点燃哪些蜡烛,使得它的n根蜡烛能用尽量多的晚上。输出最多能用多少个晚上。
输入格式:
第一行:两个整数n,c,1 <= n,c<=1000000
第二行:n个整数,第i个整数表示第i根蜡烛的长度h[i]。1 <= h[i] <= 1000000
输出格式:
一个整数,总共最多能用多少个晚上
数据范围:
对于 30% 的数据, 1 <=n,c<=1000。
对于 100% 的数据, 1 <=n,c<=10^6。
样例输入:
3 3
2 2 2
样例输出:
2
这题出得非常的好,想解决这题,要利用前缀和,数组下标,二分法,所以我一开始的思路是这样的
#include <bits/stdc++.h>
using namespace std;
long long n,m,x,p,k,l,r,a[10000009],b[10000009],c[10000009],mid,sum;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>x;
sum+=x;
k=max(k,x);
a[x]++;
}
for(int i=1000000;i>=1;i--)b[i]=b[i+1]+a[i];
for(int i=1;i<=1000000;i++)c[i]=c[i-1]+a[i]*i;
int l=0;
r=INT_MAX;
for(;;)
{
mid=(l+r)/2;
if(mid>k)p=c[k]/mid;
else p=b[mid]+c[mid-1]/mid;
if(p>=m)l=mid;
if(p<m)r=mid;
if(l+1==r)break;
}
sum=l;
cout<<sum;
return 0;
}
但只拿了80分,后来研究来研究去,原来是r的值没有取对,正确代码如下
#include <bits/stdc++.h>
using namespace std;
long long n,m,x,p,k,l,r,a[9999999],b[9999999],c[9999999],mid,sum;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>x;
sum+=x;
k=max(k,x);
a[x]++;
}
for(int i=10000000;i>=1;i--)b[i]=b[i+1]+a[i];
for(int i=1;i<=10000000;i++)c[i]=c[i-1]+a[i]*i;
l=0;
r=1e12+1;
for(;;)
{
mid=(l+r)/2;
if(mid>k)p=c[k]/mid;
else p=b[mid]+c[mid-1]/mid;
if(p>=m)l=mid;
if(p<m)r=mid;
if(l+1==r)break;
}
sum=l;
cout<<sum;
return 0;
}