C. Anton and Fairy Tale
题意
一个谷仓的总容量为 n 。初始谷物数量为 n ,每天开始的时候都会新增谷物数量为 m (若超出容量上限,则多余部分不进入谷仓,直接丢弃)。
对于第 i 天,在该日结束的时候会被麻雀吃掉数量为 i 的谷物(若谷物不足,则吃掉当前所有谷物)。
问第几天谷仓第一次为空?
分析
首先想象谷物增减情况。
第一天开始新增谷物数量 m ,总量为 n 。第一天结束减少谷物数量 1 ,总量为 n-1 ;
第二天开始新增谷物数量 m ,总量为 n 。第二天结束减少谷物数量 2 ,总量为 n-2 ;
…
第m天开始新增谷物数量 m ,总量为 n 。第m天结束减少谷物数量 m,总量为 n-m;
第 m+1 天开始新增谷物数量为 m ,总量为 n 。第 m+1 天结束减少谷物数量 m+1,总量为 n-m-1;
第 m+2 天开始新增谷物数量为 m ,总量为 n-1 。第 m+2 天结束减少谷物数量 m+2,总量为 n-m-1-2 ;
第 m+3 天开始新增谷物数量为 m ,总量为 n-1-2 。第 m+3 天结束减少谷物数量 m+3 ,总量为 n-m-1-2-3 ;
…
观察上述模拟的计数,可以得出几个简单结论:
- 当 n≤m 时,第 n 天谷物数量即为 0 。(Hack 点)
- 当
n>m
时,
- 前 m 天开始时谷仓始终是满的。
- 对于 m 天之后,每天结束时的谷物总量为 n−m−Σi=m+1(i−m) 。故对此公式二分枚举 i 的情况,判定何时第一次取到 0 。(需要注意此处的 1≤n, m≤1018 )
代码
#include<bits/stdc++.h>
using namespace std;
long long n, m;
long long cal(long long d) {
if(d%2 == 0) return d/2*(d+1);
else return (d+1)/2*d;
}
long long get() {
long long l = 1, r = 2000000000, mid, ans = 1;
while(l <= r)
{
mid = (l+r)>>1;
if(cal(mid) >= n)
r = mid - 1, ans = mid;
else l = mid + 1;
}
return ans;
}
int main()
{
scanf("%I64d %I64d",&n,&m);
if(n > m) {
n -= m;
printf("%I64d\n",m + get());
}
else
printf("%I64d\n",n);
}