第十四届华中科技大学程序设计竞赛决赛 B Trees on Sale (脑洞题)

点击打开链接


题意:

给你一个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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值