f(n)表示问题的解
第一步:将n0 = n分成三部分a1 ,b1= 1, n1;其中a1 = n0 - n1 - 1,a1 〉= n1;
n1 是之后要分解的 ,可行解为 f(n1)
我们得到 a1,b1, f(n1)
- 前n1天,用n1(会拆开)支付,解为f(n1)
- 第n1+1天用 b1支付
- 第n1+2天用a1(完整的)支付,必须找零a1 - 1,店主有n1+1个,所以必须有 a1-1 < = n1+1
综上: n1 = floor(n0/2) - 1;
.......
第(k+1)步:这一步求 f(nk)
分解nk 为 a(k+10, b=1, n(k+1),其中a(k+1) = nk - 1 - n(k+1),a(k+1) 〉= n(k+1)
n(k+ 1) 是之后要分解的 ,可行解为 f(n(k+1))
得到的是 a1, a2 ..........ak, a(k+1), (k+1)个1, f(n(k+1))
- 前n(k+1)天,用f(n(k+1))支付
- 之后的k+1天用所有的1支付
- 之后必须用a(k+1)支付, 找零 a(k+1) - 1, 店主又n(k+1)+ k + 1 个,所以 a(k+1)-1 <= n(k+1)+k+1
n(k+1) 越小越好
n(k+1) = floor((nk-k-2)/2)
终止条件:第k步中分解nk时, 如果nk -k <= 1
因为k可以表示1的个数,满足条件说明不需要分解nk了。
举例:n=147,
k | a | b | nk |
0 | 147 | ||
1 | 74 | 1 | 72 |
2 | 37 | 1 | 34 |
3 | 18 | 1 | 15 |
4 | 9 | 1 | 5 |
解:74, 37, 18, 9, 5, 1, 1, 1, 1
==========================================
#include <stdio.h>
long long n;
int k = 0; //!< how many ones we have; which step we are in.
int main()
{
scanf("%lld", &n);
while (n - k > 1) {
n = (n - k - 2) >> 1;
++k;
}
printf("%d\n", k);
return 0;
}