很明显,可以通过二分x的方式将极值问题转化为判定性问题。
暴力的方法是直接模拟每一天还的牛奶量,复杂度O(klogn),能过四个点。
考虑优化二分的判定函数。我们将还的过程分为两部分。前一部分每次还的牛奶量都大于M,后一部分则等于M。
容易发现,在前一部分的某些情况下,会有连续几天还同样的牛奶量。考虑从这个方向去优化复杂度。
设r为未还的奶量,这种情况下连续p天还q加仑。根据题意,q=xr
推式子:
⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧⌊xr−(p−1)⋅q⌋=q⌊xr−p⋅q⌋<q
去掉下取整
⎩⎪⎪⎪⎨⎪⎪⎪⎧xr−(p−1)⋅q≥qxr−p⋅q<q
整理
⎩⎪⎨⎪⎧r−p⋅q+q≥q⋅xr−p⋅q<q⋅x
⎩⎪⎪⎪⎨⎪⎪⎪⎧qr−p+1≥xqr−p<x
qr−x<p≤qr−x+1
因为p是一个整数,所以p=⌊qr−x+1⌋
这样的话,我们就可以一次性算出很多天的还奶量了。后半部分的计算非常简单,直接除一下即可。
复杂度O(nlogn)
代码(所有变量的定义与前文相同)
#include<iostream>
#define int long long
using namespace std;
int n,k,m;
bool judge(int x){
int r=n,d=k;//d是剩余的天数
while(1){
int p,q;
q=r/x;
if(q<=m){
return m*d>=r;//处理第二部分
}
p=r/q-x+1;
if(p>d)p=d;//注意天数要在范围之内
r-=p*q;
d-=p;
if(r<=0)return 1;
if(d==0)return 0;
}
}
signed main(){
cin>>n>>k>>m;
int l=1,r=n,mid;
while(l<r){
mid=(l+r+1)>>1;//这里的二分边界要注意一下
if(judge(mid))
l=mid;
else r=mid-1;
}
cout<<l;
return 0;
}