题意:
给你一个n,k表示总共有n个顾客,每一个顾客要求的树苗数不大于k
问你最少商家需要准备多少捆树苗以满足n,k下任何一种可能的情况。不同捆的树苗里面的树苗数可以不同。
3 4 就需要准备3捆1个的树苗,2捆2个的树苗,1捆1个的树苗,1捆4 个的树苗,总共7捆
解析;
先上官方题解
设当前有x个树苗。不断加入有(x/n)+ 1个的一捆,直到x>=n*k为止。
意会一下。出题人表示心很累,不想写证明了。
.....我看了也看不懂,然后找了一些ac代码,看了一下,就大概臆测了一下,以下内容不保证其一定正确:
遍历一个顾客的要求树苗数i,我们判断当前的树苗数sum和该种情况下需求最大的树苗情况,即最大的可能就是i*n(n个顾客全部要了i),那么其中的差距i*n-sum,就是我们需要用i个一捆的树苗来弥补的,因为这样才能使得总的捆数最小。但是按照遍历顾客的需求的算法复杂度达10^12,所以优化就是其中存在一些无效的查找。就是当有一些遍历到一些i时,i*n<sum,即当前的总树苗数>i需求下的最大情况,那么我们一定可以用sum,来满足需求i下的各种情况(至于原因...我也不知道,代码里就是这么写的)
#include <cstdio>
#include <cstring>
typedef long long int ll;
const int MAXN = 2e5+10;
int main()
{
ll n,m;
while(scanf("%lld%lld",&n,&m)!=EOF)
{
ll sum=0;
ll ans=0;
ll sta=n*m;
for(ll i=1;i<=m&&sum<=sta;i=sum/n+1)
{
ll tmp=i*n;
if(sum<tmp)
{
ll gap=tmp-sum;
if(gap%i==0)
{
ll cn=gap/i;
ans+=cn;
sum+=cn*i;
}
else
{
ll cn=gap/i+1;
ans+=cn;
sum+=cn*i;
}
}
}
printf("%lld\n",ans);
}
return 0;
}
标程:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
long long ans,n,k;
int main()
{
while(scanf("%lld%lld",&n,&k)!=EOF)
{
ans=0;
for(long long i=0;i<n*k;i+=(i/n)+1)ans++; //遍历答案
printf("%lld\n",ans);
}
return 0;
}