Triple Operations 的题解
记住只在没有思路时使用题解,不要从它复制粘贴代码。请尊重题目和题解的作者。
在解题之前提交题解的代码会导致封禁。
在解题之前提交题解的代码会导致封禁。
作者:
概述
本题要求计算将区间 内所有整数通过指定操作变为
所需的最少操作次数。核心解法利用三进制表示,将操作视为给一个数末尾添零、给另一个数删去末位,最终答案等于
,其中
为
的三进制位数。
分析
核心观察
一次操作将 变为
(三进制末尾补
),将
变为
(三进制删去末位)。只有当
时,
仍为
,不会增加位数,此时总位数减少
。
思路
将每个数写成三进制形式。操作不改变所有数的总位数,除非选择 ,此时总位数减少
。最终所有数变为
(位数为
),因此必须通过若干次“零操作”来消耗掉所有初始位数。
要构造最少操作,应尽快得到一个 。对某个数
,使其变为
需要连续除以
直到为
,即
次操作(每次选它为
,且另一个数任意非零?但还需考虑同时给另一个数补零,但补零不会消耗位数,只要另一个数非零,总位数不变;若另一个数为零则消耗位数,但这个过程本身会使目标数逐步减少)。为减少总操作,第一步应选择区间内最小的数
,因为它位数最少,
最小,将其变为
需
次。
一旦获得 ,之后每次操作选择
,
为某个未归零的数,即可消耗
的一位,同时
保持
。要消除所有数的全部位数,总共需要消除
位(因为每个数初始有
位,最终都要变为
)。因此总操作次数为第一步的
加上所有数的位数总和,即:
其中 ,且
(但
)。
预计算 的前缀和
,则每个测试用例的答案为:
具体示例
以样例第一组 为例:
,
(三进制
2 一位),(三进制
10 两位)。
总和 ,再加
,得
,与输出一致。
第二组 :
,总和
,加
得
。
算法步骤
- 预处理
(
从
到最大可能的
,即
)。
- 计算前缀和数组
psum,其中psum[i] = psum[i-1] + f(i)。 - 对每个测试用例,读入
。
- 计算答案
ans = f(l) + psum[r] - psum[l-1]。 - 输出
ans。
复杂度分析
- 时间:预计算
,其中
;每个测试用例
。
- 空间:
用于存储
和前缀和数组。
实现注意事项
- 最大
为
,预计算范围可设为
或稍大(如
)。
可通过循环整除
得到,注意当
时返回
,但输入
,计算时只用正数。
- 前缀和数组需使用 64 位整数(如
long long)存储,因为约
,对
约
,还在
int范围内(),但为安全仍用
long long。 - 多组测试数据,使用快速输入输出。
源代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200000 + 5;
long long fval[MAXN], pref[MAXN];
int f(int x) {
int cnt = 0;
while (x > 0) {
x /= 3;
++cnt;
}
return cnt;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
for (int i = 1; i < MAXN; ++i) {
fval[i] = f(i);
pref[i] = pref[i - 1] + fval[i];
}
int T;
cin >> T;
while (T--) {
int l, r;
cin >> l >> r;
long long ans = fval[l] + (pref[r] - pref[l - 1]);
cout << ans << '\n';
}
return 0;
}
import sys
MAXN = 200000 + 5
fval = [0] * MAXN
pref = [0] * MAXN
def f(x):
cnt = 0
while x > 0:
x //= 3
cnt += 1
return cnt
for i in range(1, MAXN):
fval[i] = f(i)
pref[i] = pref[i-1] + fval[i]
def solve():
data = sys.stdin.read().strip().split()
if not data:
return
t = int(data[0])
out = []
idx = 1
for _ in range(t):
l = int(data[idx]); r = int(data[idx+1]); idx += 2
ans = fval[l] + (pref[r] - pref[l-1])
out.append(str(ans))
sys.stdout.write("\n".join(out))
if __name__ == "__main__":
solve()
评论