codeforces #476 div2 D(math)

题目给定四个参数n,k,M,D   1<=M<=n  D=min(n,1000);  1<=k<=n;    n<=1*10^18

要求将n个糖果分配给k个人,要求每个人最多只能被分配D次(最多D次),分配方式是选定x,从第一个人开始没人拿x个,并循环拿走,直到剩下的糖果不足x个,丢弃。问第一个人最多能够拿到多少糖果。

首先n,M十分大,没有办法进行直接枚举计算。但是分配次数,最大是1000次,可以以此为突破口。

当然第一开始会本能的去算一下x的存在区间 上线为M ,下线满足  x*(k*D + 1) -1 <=n   那么x下线约为n/k/D,参考取值范围,上下线差别远超枚举计算可行范围。

考虑没人最多分配d次,那么 分配d次,第一个最多可以拿到的糖果为 (n/((d -1 ) * k + 1)) * d  , 其中(d -1)* k + 1为求得的每次分配的x经过d-1轮分配之后最少需要剩余x个,以便于分配给第一个人,这样求得的x为x的最大值,当然这就意味着比x小的值都可以完成d次分配,或者更多轮分配。

注意这里求得的x要和M取最小值。

来解释一下为何可以直接取两者的最小值,因为当前求得的是满足完成d次分配的最大值,假设上轮d+1次分配最大值为x2,因为上一轮没有取到M,那么x2<M<=x,即M此时是可以并且只能完成d次分配的一个备选x


#include<cstdio>

#include<iostream>
#include<algorithm>
using namespace std;


const int N  = 102;


unsigned long long n, k ,M ,D;
int main()
{
    cin>>n>>k>>M>>D;
    unsigned long long ans = M;
    for(unsigned long long i = D ; i>=1 ; i--){
         if(i-1 > 0 && n / (i - 1)/ k <=0) continue;
         ans = max(ans , (i) * min((n/((i - 1) * k + 1)), M));
    }
    cout<<ans<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值