Description
有(n)个木棍,长度为(1,2,3...n),现在要从中删掉一些木棍,使得剩下的木棍不能构成三角形,使删掉木棍的数量最少。T
组数组,(T leq 20)
(n leq 20)
Solution
由于数据范围很小,可以直接暴力求解,依次选取两个数(a,b(a<b))相加,要知道不能有任何一个数小于这个值,直接删掉((a,a+b))范围中的数即可
如果(n)的范围是(1e9)呢?
通过找规律发现我们剩下的数是这样的
(1,2,3,5,8,13,21...)
这是Fibonacci数列!!!!
所以我们只需要找到(leq n)的Fibonacci数有几个,减去就是答案
可以直接lower_bound
注意处理极限数据!!!即(n==1||n==2)的情况
也可手写二分,但是二分貌似常数有点大,又考虑到第(88)个Fibonacci数就爆掉(1e9)了,所以直接便利也完全没问题
Code
暴力版本
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <queue>
using namespace std;
bool vis[23];
int main() {
int T;
cin >> T;
for (int i = 1; i <= T; i++) {
int N, ans = 0;
cin >> N;
memset(vis, false, sizeof(vis));
for (int j = 1; j <= N - 1; j++)
if (!vis[j]) {
for (int k = j + 1; k <= N; k++) {
if (!vis[k]) {
for (int l = k + 1; l <= j + k - 1; l++)
if (!vis[l] && l <= N) vis[l] = true, ans++;
break;
}
}
}
printf("Case #%d: %d
", i, ans);
}
return 0;
}
二分+Fib
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <queue>
typedef unsigned long long uLL;
typedef long long LL;
const LL MOD = 1e18;
using namespace std;
LL f[100];
int main() {
f[0] = 1;
f[1] = 1;
for (int i = 2; i <= 80; i++)
f[i] = f[i - 1] + f[i - 2];
int T;
cin >> T;
for (int i = 1; i <= T; i++){
LL N;
cin >> N;
if (N == 1 || N == 2) {
printf("Case #%d: 0
", i);
continue;
}
int l = 1, r = 80;
/*手写二分查找
while (l <= r) {
int mid = (l + r) >> 1;
if (f[mid] <= N) l = mid + 1;
else r = mid - 1;
}
int pos = l;
*/
int pos = lower_bound(f, f + 80, N) - f;
if (f[pos] != N) pos--;
printf("Case #%d: %d
", i, N - pos);
}
return 0;
}