题解:P9362 Find Maximum
思路分析
考虑对于一个 \(x\) 如何求出 \(f(x)\) 的值。
就是如下的操作次数:
- 如果 \(x\) 为 \(0\) 操作结束;
- 如果 \(x\) 是 3 的倍数,令 \(x\gets x\div 3\);
- 如果 \(x\) 不是 3 的倍数,令 \(x\gets x-1\)。
不妨将操作翻转,发现操作 2 等价于将 \(x\) 在三进制下左移一位;操作 3 等价于将 \(x\) 在三进制下加一,且不会进位。那么原命题转化为在 \([l,r]\) 内求一个数使得它在三进制下的数位和位数之和最大。
这可以用数位 DP 解决。时间复杂度 \(O(S+T\times\log_3 R)\)。
代码实现
Code
#include<bits/stdc++.h>
using namespace std;
const int N = 105;
int a[N], b[N], dp[N][N * 2];
inline int dfs(int idx, int sum, int lead, int limit, int dlim){
int res = 0;
if(idx == 0) return lead ? 1 : sum;
if(!lead && !limit && !dlim && dp[idx][sum]) return dp[idx][sum];
int up = limit ? a[idx] : 2, down = dlim ? b[idx] : 0;
for(int i = down; i <= up; i++)
res = max(res, dfs(idx - 1, sum + i + !lead, lead & (i == 0), limit & (i == up), dlim & (i == down)));
if(!lead && !limit && !dlim) dp[idx][sum] = res;
return res;
}
int main(){
int T; cin >> T;
while(T--){
long long l, r;
cin >> l >> r;
int n = 0, m = 0;
memset(a, 0, sizeof(a)), memset(b, 0, sizeof(b));
while(r) a[++n] = r % 3, r /= 3;
while(l) b[++m] = l % 3, l /= 3;
int ans = dfs(n, 0, 1, 1, 1);
cout << ans + 1 << '\n';
}
return 0;
}

浙公网安备 33010602011771号