专栏文章

题解:P11397 界分数

P11397题解参与者 4已保存评论 3

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
3 条
当前快照
1 份
快照标识符
@miqqelym
此快照首次捕获于
2025/12/04 09:02
3 个月前
此快照最后确认于
2025/12/04 09:02
3 个月前
查看原文

看前人的题解我是一头雾水。

我来写一篇通俗易懂的题解。

明确策略

首先,约掉 22 的利益是最大的,这不难理解:
每执行一次操作(除第一次操作),都能约掉一个 22,所以,如果每一次操作都约掉一个 22,那么共执行 log2n\log_2n 次操作。如果说要约掉一个 33,那么至少要执行两次操作,但如果这两次操作每次约掉一个 22,则相当于约了一个 44,显然利益更大;同理,要约掉一个 44,就要执行三次操作,也没有约 22 的利益大。以此类推,可知约掉 22 的利益是最大的。
每一次都必然能约掉一个 22,这也不难理解,只需:当分母为奇数,执行操作 22;反之,执行操作 11
其次,再考虑第一次操作,应执行操作一,下面给出样例解释。
88总执行次数
执行操作118\frac {1}{8}14\frac {1} {4}12\frac {1} {2}1144
执行操作219\frac {1} {9}15\frac {1} {5}13\frac {1} {3}12\frac {1} {2}1155
显然,先执行操作 22 可能会多执行一次操作。
那么,我们的策略就是:第一步执行操作 11,之后分母为偶执行执行操作 11,分母为奇执行执行操作 22

计算过程

已经明确了策略,下一步就是如何计算了。
直接模拟很显然会 TLE,那就要用数学方法。
已经知道执行步数是 (log2n)+1\left(\log_2 n \right)+ 1,但若是每个数都进行计算,还是会 TLE。
所以,这道题旨在减少计算。那就来找一找规律:
112233445566
操作次数112233334444
这样看可能不太明显,我们换一种方式:
  1. 1=11 = 1\\
  2. 2=1+12 = 1 + 1\\
  3. 3=1+1+13 = 1 + 1 + 1\\
  4. 3=1+1+13 = 1 + 1 + 1\\
  5. 4=1+1+1+14 = 1 + 1 + 1 + 1\\
  6. 4=1+1+1+14 = 1 + 1 + 1 + 1\\
  7. 4=1+1+1+14 = 1 + 1 + 1 + 1\\
  8. 4=1+1+1+14 = 1 + 1 + 1 + 1\\
  9. 5=1+1+1+1+15 = 1 + 1 + 1 + 1 + 1\\
这么看来,我们可以竖着加,即每遇到一个 22 的倍数 tt,就加 ntn - t。这样,可以大大减小时间复杂度。
CPP
#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。那只有可能是在 mod 998244353\bmod \ 998244353 时出现了问题。仔细观察可以发现,最后一个 subtask 的数据超极大,直接加减会超出 long long 数据类型的范围。所以,要稍作改动,先 mod 998244353\bmod\ 998244353,再加减。
CPP
#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;
}

评论

3 条评论,欢迎与作者交流。

正在加载评论...