本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
【ICPC】2022西安站 E. Find Maximum | 三进制
像是传统二进制题目的三进制版本(
题目链接
Problem - E - Codeforces
题目

题目大意
对一个正整数 x 定义函数
f(x)=⎩⎨⎧1f(3x)+1f(x−1)+1(x=0)(x>0∧(3∣x))(x>0∧(3∤x))
给定 l 和 r,求 maxi=lr(f(x))。
多组数据。
思路
看到题第一眼感觉答案最大的一定是 ((2∗3+2)∗3+2)∗3+2...
然后发现这非常类似于常见的二进制问题,首先我们将 x 转化为 3 进制形式,容易发现 f(x) 实际上就是各个数位上的数字加一求和。如 342 按照上述过程我们可以计算出
f(342)=f(114)+1=f(38)+1+1=f(37)+1+1+1=f(36)+1+1+1+1=f(12)+1+1+1+1+1=f(4)+1+1+1+1+1+1=f(3)+1+1+1+1+1+1+1=f(1)+1+1+1+1+1+1+1+1=f(0)+1+1+1+1+1+1+1+1+1=1+1+1+1+1+1+1+1+1+1=10
实际上在三进制的视角下,就是把末位减到 1,再扔掉 0,直到把整个数变成 0。 342 的三进制形式为 (110200)3, 则
f(342)=(1+1)+(1+1)+(0+1)+(2+1)+(0+1)+(0+1)=2+2+1+3+1+1=10
所以我们可以用处理二进制下该类问题的方式,类似地处理三进制问题。
最初 x=0,自高向低处理到第 i 位时,试图让 x 的当前位为 ri−1,后面的数位全部填上 2。若 x 这样填充后比 l 大,就可以用 x 来更新答案。然后我们把 x 的第 i 位填上 ri 继续进行上述过程。
代码
#include <bits/stdc++.h>
using namespace std;
using LL=long long;
int T,l[41],r[41];
LL L,R,x,bas[41],sum,ans;
const int N=38;
int main()
{
bas[0]=1;
for (int i=1;i<=N;++i) bas[i]=bas[i-1]*3;
for (scanf("%d",&T);T--;)
{
x=ans=sum=0;
scanf("%lld%lld",&L,&R);
for (int i=N-1,flag=0;i>=0;--i)
{
l[i]=L%bas[i+1]/bas[i];
r[i]=R%bas[i+1]/bas[i];
if (r[i]!=0) flag=1;
if (!flag) continue;
if (r[i]!=0&&(x+r[i]*bas[i]-1)>=L)
{
if (r[i]==1&&sum==0) ans=max(sum+i*3ll,ans);
else ans=max(sum+r[i]+i*3ll,ans);
}
sum+=r[i]+1;
x+=r[i]*bas[i];
}
printf("%lld\n",max(ans,sum));
}
return 0;
}