题目描述
小明正在为四级做准备,他计划至少背 nn 个新单词。
为了完成这个目标,小明决定在每天结束前背一些新单词,具体来说:
第 11 天结束前,小明会背 mm 个新单词;
第 ii 天( i≥2i≥2 )结束前,小明会根据第 i−1i−1 天背的单词数计算第 ii 天背多少个新单词
假设小明在第 i−1i−1 天背了 tt 个新单词:
如果 tt 是奇数,小明将会在第 ii 天结束前背 3×t+13×t+1 个新单词;
如果 tt 是偶数,小明将会在第 ii 天结束前背 t22t 个新单词。
现在小明想知道按照这个方式背单词,最早在第几天结束时累计背了至少 nn 个新单词。
输入描述:
输入一行,包含两个整数 n,mn,m ,分别代表小明计划背的新单词总数和小明第一天背的新单词数量。
输出描述:
输出一行,包含一个整数 dd ,代表小明在第 dd 天结束时累计背了至少 nn 个新单词。
示例1
输入
复制
100 50
输出
复制
3
备注:
【样例解释】
第一天背了 5050 个新单词,第二天背了 2525 个新单词,第三天背了 7676 个新单词,累计背了 151151 个新单词,最早在第三天结束时完成了背至少 100100 个新单词的计划。
【评测用例规模与约定】
对于 70%70% 的评测用例, 1≤n≤106,1≤m≤10001≤n≤106,1≤m≤1000 。
对于 100%100% 的评测用例, 1≤n≤1012,1≤m≤10001≤n≤1012,1≤m≤1000 。
解题思路
可以根据题意进行模拟,由于
很大暴力模拟会超时,注意开 long long
。
上述式子实际上是冰雹猜想,即任意一个
用以上式子计算最终都会进入 4-2-1
的循环。由于 很小,如果不知道这个结论也可以对 逐个进行验证(虽然无法证明冰雹猜想是否完全正确,但是在
的数据范围下一定是正确的)。
进入循环时,可以将循环的 4-2-1
进行打包处理,即 3 天为一组,每组的大小都为
。
假设进入循环时剩余的单词数为
,打包处理即答案累加上 ,然后 对 进行取模,剩下的继续循环模拟,继续模拟的次数不会超过
次。
进入循环的判定即
或 或
。
参考代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
ll n, m;
cin >> n >> m;
ll ans = 0;
while (n > 0) {
ans++;
n -= m;
if (m % 2) {
m = 3 * m + 1;
} else {
m /= 2;
}
// 在模拟的基础上,打包循环的部分
if (m == 1 || m == 2 || m == 4) {
ans += (n / 7) * 3;
n %= 7;
}
};
cout << ans << '\n';
return 0;
}
个人总结
感觉这种题主要是靠找规律,考的主要是思维,一般人应该不易想出。
他的核心思想是通过循环简化算法。