真的是。。越来越菜了。拿到一道题过不了心态就爆炸。
题目:http://codeforces.com/problemset/problem/785/C
题目意思:
有一个仓库。容量为n,每天会补充m的粮仓,如果补的库存量加上仓库原有库量超过了容量,仓库里的库存量就为n,每一天都会有小鸟来啄走粮食,每个小鸟每天就只能啄走1个单位的粮食,但每过一天就会多一只小鸟,现在问这个仓库的粮仓什么可以支持多少天后库存量为0,注意:是小鸟先啄食,再补粮仓。拿到题感觉很准,不就是一道公式题嘛,求一个不等式的解,向上取整,于是默默的列出了一个不等式
n - d * (d + 1) / 2 + (d - 1) * m >= 0
没错就是这个不等式。。让我搞了一个晚上。。不知道为什么当时脑抽的加上了(d - 1) * m。。明明我的d是应该从m天以后开始的,就不需要加(d - 1) * m了这是wa了一个晚上的想法。。下面说说这题的正解
当m >= n的时候,每次都肯定可以补满粮仓,所以只有当小鸟数到达n的时候,才能将粮仓清零,所以这种情况的答案应该是n
当m < n时,第m天前,所有粮仓库存量都是可以补满的,所以只需要管后面还需要多少天即可。
可以列出不等式n - m - d * (d + 1) / 2 < 0,表示n的库存量,在第d天的时候库存量要小于0,求最小的那个d, 很容易可以解出方程为-0.5 + sqrt(0.25 + 2 * (n - m)),但是很遗憾,sqrt这个只是double,精度并不够,所以有个队友提出了。。二分。
二分去check他这个式子是否满足(由于这个式子是单调递减的,所以可以选择使用二分),还有一点很重要的d * (d + 1)这个会爆ll的,所以应该先除后乘,但是依旧遇到很奇怪的事情,除2也会爆ll,所以我选择了*0.5。。这难道就是魔法。后来又想,怎么才能解决爆精度的问题,于是想到,再check一次答案而否正确,不正确的话,天数就得+1,因为有一点点的精度问题嘛。
代码:
二分:
/*
@resouces: codeforces
@date: 2017-3-17
@author: QuanQqqqq
@algorithm:
*/
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll n,m;
ll check(ll day){
return -day * 0.5 * (day + 1) + n - m <= 0;
}
ll binary_search(ll l,ll r){
ll mid,ans;
while(l <= r){
mid = l + r >> 1;
if(check(mid)){
r = mid - 1;
ans = mid;
} else {
l = mid + 1;
}
}
return ans;
}
int main(){
while(~scanf("%lld %lld",&n,&m)){
if(n <= m){
printf("%lld\n",n);
continue;
}
printf("%lld\n",binary_search(0,1e18) + m);
}
}
公式法:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main(){
ll n,m;
while(~scanf("%lld %lld",&n,&m)){
if(n <= m){
printf("%lld\n",n);
continue;
}
ll ans = (ll)ceil(-0.5 + sqrt(0.25 + 2 * (n - m)));
if(ans * ans + ans - 2 * (n - m) < 0){
ans++;
}
printf("%lld\n",m + ans);
}
return 0;
}