题目给定四个参数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;
}