题意:给你一系列糖果,每个糖果有一个起始的价值 ai ,我们每天都会获得x元,不可积累,每种糖果每天只能买一个,每天,所有糖果都会涨价+1元,问最多能买到多少糖果?
分析:我们可以先排个序,因为贪心地想,肯定是先买最便宜的糖果更加省钱。然后如果我们买了第一个糖果 a1 ,那么达成什么条件才能买第二个呢,当然是
所以第二个突破点,我们很自然的想到要用前缀和s[i] 来判断
最后,如何判断某种糖果可以买多少个呢?
性质 : 前多少件物品价值不超过 m(给定的价值)
//二分出前i件物品;
//从题目中可以发现 性质:和<=m,和>m;
// s[i]<=mid; 寻找到右端点, 而下标数,就是和不超过m的最多个数;
#include <iostream>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
const int N=200010;
int n,m;
int a[N];
bool check(int mid)
{
int ans=0;
for(int i=1;i<=mid;i++)
{
ans+=a[i];
}
if(ans<=m)return true;
else return false;
}
void solve()
{
int ans=0;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
sort(a+1,a+n+1);
while(1)
{
int l=0,r=n;// 下标
while(l<r)
{
int mid=l+r+1>>1;
//性质: <=7 的个数;
if(check(mid)) l=mid;
else r=mid-1;
}
ans+=l;
for(int i=1;i<=n;i++)
{
a[i]+=1;
}
if(a[1]>m)break;
}
cout<<ans<<endl;
}
signed main()
{
int t;
cin>>t;
while(t--)
{
solve();
}
}
TLE 优化为前缀和
#include <iostream>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
const int N=200010;
int n,m;
int a[N];
int s[N];
void solve()
{
int ans=0;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)
{
s[i]=s[i-1]+a[i];
}
if(a[1]>m)
{
cout<<ans<<endl;
return ;
}
while(1)
{
int l=0,r=n;// 下标
while(l<r)
{
int mid=l+r+1>>1;
//性质: <=7 的个数;
if(s[mid]<=m) l=mid;
else r=mid-1;
}
ans+=l;
for(int i=1;i<=n;i++)
{
a[i]+=1;
s[i]+=i;
}
if(a[1]>m)break;
}
cout<<ans<<endl;
return ;
}
signed main()
{
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
TLE,继续优化前缀和,因为第一次找到的那个下标之后的数一点不会再被计算到,因为每次a[i]在+1;
#include <iostream>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
const int N=200010;
int n,m;
int a[N];
int s[N];
void solve()
{
int ans=0;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)
{
s[i]=s[i-1]+a[i];
}
while(1)
{
int l=0,r=n;// 下标
while(l<r)
{
int mid=l+r+1>>1;
//性质: <=7 的个数;
if(s[mid]<=m) l=mid;
else r=mid-1;
}
ans+=l;
for(int i=1;i<=l;i++)
{
s[i]+=i;
}
a[1]+=1;
if(a[1]>m)break;
}
cout<<ans<<endl;
return ;
}
signed main()
{
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
还是TLE了。放弃二分,看题解。