思路整理:1.简述:k头奶牛,n个布丁,每头牛一次发x个布丁。
规定:x<=M,单个次数(d)<=D。
2.因题目要求D的数据范围相对较小,故作为此题突破口,进行枚举次数(1<=d<=D)。
3.约翰一共会发floor(n/x)次布丁,总次数范围(d-1)*k+1<=floor(n/x)<=d*k(式①)。
4.1<=x<=M,目的:使1号奶牛的布丁数最多,即d*x最大;d在枚举时为确定值,因此需 要x最大(转化思路);
5.对于n/x,x越大,n/x越小,对于式①来说,左边越来越可能不满足,右边越来越可能满足,所以只需要在[1,M]范围内找满足左边不等式的x的最大值,然后验证其是否满足右边的不等式,因为n/x关于x单调递减,故利用二分法求解(时间复杂度O(D*log以2为底10的18次方));
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ll n,k,M,D,d,xx,l,r,m;
cin>>n>>k>>M>>D;
ll ans=0;
for(d=1;d<=D&&(d-1)*k+1<=n;++d){ //枚举次数d,d<=D,x>=1,发放布丁最小总次数(d-1)*k+1<=n/x<=n(防止爆long long);
l=1; //对x二分
r=M;
while(l<r){
m=(l+r+1)/2; //+1避免死循环
if((n/m)>=(d-1)*k+1) l=m; //如果>=不等式下界,更新下界
else r=m-1; //如果<不等式下界,更新上界
}
if(n/l<=d*k) ans=max(ans,d*l); //如果符合要求,取最大可能值
}
cout<<ans<<endl;
return 0;
}
6.也可直接求解,记y=(d-1)*k+1,y<=floor(n/x)<=n/x,故x*y<=n,x<=n/y,即x<=floor(n/y),求得x的上界;
通过带余除法证明floor(n/floor(n/y))>=y:
设n=a*y+r,0<=r<y;floor(n/floor((a*y+r)/y))=floor(n/a)=floor((a*y+r)/a)>=floor(a*y/a)=y;
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ll n,k,M,D,y,x,d;
cin>>n>>k>>M>>D;
ll ans=0;
for(d=1;d<=D;++d){ //枚举次数d,d<=D;
y=(d-1)*k+1; //发放布丁的最小总次数<=n/x<=n
if(y>n) break; //如果总次数>n ,退出
x=min(M,n/y); //已知x两个上界,x必须同时满足 ,故取最小值
if(n/x>=y&&n/x<=d*k) ans=max(ans,d*x); //满足不等式①,更新ans,求满足条件的最大可能值
}
cout<<ans<<endl;
return 0;
}