[HDU 6156] Palindrome Function

题意:
我们定义

\[ f(n, k)=\left\{ \begin{aligned} k& \ (n在k进制下为回文串) \\ 1& \ (其余情况) \\ \end{aligned} \right.\]

\(\sum_{i=L}^{R}\sum_{j=l}^{r}f(i, j)\)

题解:
题意很明显往数位\(dp\)去靠,但是要求回文串,所以要记录下前面枚举的数位的数字是什么。同时要注意到前导\(0\)的情况,这会让你枚举的数字长度减少。并且只要有一个地方没有对应上,该串就无法形成回文串。我们定义\(dp[len][pos][k][good]\),代表当前枚举的数字长度为\(len + 1\),枚举到第\(pos\)位,在\(k\)进制下,之前对应位置的数字若能对应则\(good\)\(1\),其余置\(0\)时,能提供的贡献是多少。当我们枚举到数位到达当前长度的一半以及更长时,进行对应位置的判断,从而将状态转移下去。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

ll dp[37][37][37][2];
int pre[37], tot, n;
int a[37], cas;
int L, R, l, r;

ll dfs(int len, int pos, int k, int good, bool lim) {
    if (pos == -1) {
        if (good) return k;
        else return 1;
    }
    if (!lim && dp[len][pos][k][good]) {
        return dp[len][pos][k][good];
    }
    int to = lim? a[pos] : k - 1;
    ll tmp = 0;
    for (int i = 0; i <= to; ++i) {
        pre[pos] = i;
        if (i == 0 && len == pos && len) tmp += dfs(len - 1, pos - 1, k, good, lim && (i == to));
        else if (good && pos < (len + 1) / 2) tmp += dfs(len, pos - 1, k, i == pre[len - pos], lim && (i == to));
        else tmp += dfs(len, pos - 1, k, good, lim && (i == to));
    }
    if (!lim) dp[len][pos][k][good] = tmp;
    return tmp;
}

ll gao(int val, int k) {
    tot = 0;
    int v = val;
    while (v) {
        a[tot++] = v % k;
        v /= k;
    }
    return dfs(tot - 1, tot - 1, k, 1, true);
}

void solve() {
    scanf("%d %d %d %d", &L, &R, &l, &r);
    ll ans = 0;
    for (int k = l; k <= r; ++k) {
        ans += gao(R, k) - gao(L - 1, k);
    }
    printf("Case #%d: ", ++cas);
    printf("%lld\n", ans);
}

int main() {
    int t = 1;
    scanf("%d", &t);
    while (t--) solve();
    return 0;
} 
posted @ 2021-03-06 00:33  stff577  阅读(51)  评论(0)    收藏  举报