3424. 最少砝码
你有一架天平。现在你要设计一套砝码,使得利用这些砝码可以称出任意小于等于 \(N\) 的正整数重量。
那么这套砝码最少需要包含多少个砝码?
注意砝码可以放在天平两边。
输入格式
输入包含一个正整数 \(N\)。
输出格式
输出一个整数代表答案。
数据范围
对于所有评测用例,\(1≤N≤10^9\)。
输入样例:
7
输出样例:
3
样例解释
\(3\) 个砝码重量是 \(1、4、6\),可以称出 \(1\) 至 \(7\) 的所有重量。
1 = 1;
2 = 6 − 4 (天平一边放 6,另一边放 4);
3 = 4 − 1;
4 = 4;
5 = 6 − 1;
6 = 6;
7 = 1 + 6;
少于 \(3\) 个砝码不可能称出 \(1\) 至 \(7\) 的所有重量。
解题思路
规律,数学,二分
先从最基本的情况考虑:
一个砝码最多称 \(1\sim 1\) 的重量
\(\color{red}{那两个砝码最多称 1\sim ? 的重量?}\)
这时由于添加了一个砝码,考虑添加的砝码重量为 \(x\),由于上一个砝码称出范围为 \(1\sim 1\),则考虑新添加的砝码的情况下,此时最少能称出的重量为 \(x-1\),不用新添加的砝码能够称出 \(1\sim 1\) 的重量了,此时只需要 \(x-1\leq 1+1\),即 \(x=3\),加上 \(1\sim 1\),即最多能称出的重量为 \(4\),此时 \(1\sim 4\) 的重量都能称出,总的来说,设 \(n\) 个砝码最多能称出 \(a_n\) 的重量,设 \(n+1\) 新增添的砝码重量为 \(x\),则 \(x-a_n \leq a_n+1\),由于要求最多,则 \(x=2\times a_n+1\),加上 \(n\) 个砝码取到的最大值,即 \(n+1\) 个砝码取到的最大值,即 \(a_{n+1}=3\times a_n+1\),即 \(a_n=\frac{3^n-1}{2}\),将各个砝码数且满足在要求的重量范围内对应的重量求出,再二分即可
\(10^9\) 以内最多用到的砝码数为 \(19\),所以:
- 时间复杂度:\(O(1)\)
代码
// Problem: 最少砝码
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/3427/
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=30;
LL f[N];
int n,cnt=1;
int main()
{
f[1]=1;
for(int i=2;3*f[i-1]+1<=1e9;i++)
f[i]=3*f[i-1]+1,cnt++;
f[++cnt]=2e9;
cin>>n;
cout<<(lower_bound(f+1,f+cnt+1,n)-f);
return 0;
}