题解:P11397 界分数
看前人的题解我是一头雾水。
我来水写一篇通俗易懂的题解。
明确策略
首先,约掉
每执行一次操作(除第一次操作),都能约掉一个
每一次都必然能约掉一个
其次,再考虑第一次操作,应执行操作一,下面给出样例解释。
| 总执行次数 | ||||||
|---|---|---|---|---|---|---|
| 执行操作1 | ||||||
| 执行操作2 |
显然,先执行操作
那么,我们的策略就是:第一步执行操作
计算过程
已经明确了策略,下一步就是如何计算了。
直接模拟很显然会 TLE,那就要用数学方法。
已经知道执行步数是
所以,这道题旨在减少计算。那就来找一找规律:
| 操作次数 |
这样看可能不太明显,我们换一种方式:
-
1 = 1\\ -
2 = 1 + 1\\ -
3 = 1 + 1 + 1\\ -
3 = 1 + 1 + 1\\ -
4 = 1 + 1 + 1 + 1\\ -
4 = 1 + 1 + 1 + 1\\ -
4 = 1 + 1 + 1 + 1\\ -
4 = 1 + 1 + 1 + 1\\ -
5 = 1 + 1 + 1 + 1 + 1\\
这么看来,我们可以竖着加,即每遇到一个
#include<bits/stdc++.h>
#define int long long//即所有的int变成long long
using namespace std;
int Mod = 998244353;
signed main()//由于有 int long long,所以此处改为signed
{
int n,t = 1;
cin >> n;
int s = n;
while(pow(2,t - 1) < n)
{
t++;
s += n - pow(2,t - 1);
s %= Mod;
}
cout << s % Mod << endl;
return 0;
}
但是,新的问题又出现了:我们可以通过前面的测试点,但最后一个 subtask 会 WA。那只有可能是在
#include<bits/stdc++.h>
#define int long long//即所有的int变成long long
using namespace std;
int Mod = 998244353;
signed main()//由于有 int long long,所以此处改为signed
{
int n,t = 1;
cin >> n;
int s = n;
while(pow(2,t - 1) < n)
{
int x = pow(2,t - 1);//pow函数返回值是double类型,要转成long long
s += (n - x) % Mod;
t++;
}
cout << s % Mod << endl;
return 0;
}