题解:P9362 Find Maximum

思路分析

考虑对于一个 \(x\) 如何求出 \(f(x)\) 的值。

就是如下的操作次数:

  1. 如果 \(x\) 为 \(0\) 操作结束;
  2. 如果 \(x\) 是 3 的倍数,令 \(x\gets x\div 3\);
  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;
}
posted @ 2026-10-06 18:34  地上飞的鱼  阅读(6)  评论(0)    收藏  举报