题目链接:https://vjudge.net/problem/HDU-6156
题意:区间[L, R]的数,写成k进制(l<=k<=r)后,如果是回文串,那么f(x,k)=k,否则f(x,k)=1,对f求和
题解:一看这种题就是数位dp,当时想的时候认为,因为要求是回文串,所以前面的数是什么对后面是有影响的,所以就不知道怎么处理了,后来一想,在没有限制的情况下,后面的数是随便取的,所以也就是说,无论前面取的什么数字,都能凑成回文的,因此dp[ i ][ j ][ k ][bas] 表示到达第 i 位,回文串开始的位置是 j ,是否还可以凑成回文串 k ,几进制 bas
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[35][35][2][38];
int w[35], len;
int num[35];
ll dfs(int pos, int state, int limit, int st, int lead, int bas) {
if(pos < 0) {
return state ? bas : 1;
}
if(!limit && dp[pos][st][state][bas] != -1) return dp[pos][st][state][bas];
int up = limit ? w[pos] : bas - 1;
ll res = 0;
for(int i = 0; i <= up; i++) {
num[pos] = i;
if(i == 0 && lead) res += dfs(pos - 1, state, limit && i == up, st - 1, 1, bas);
else if(i && lead) res += dfs(pos - 1, state, limit && i == up, st, 0, bas);
else {
if(pos >= (st + 1) / 2) res += dfs(pos - 1, state, limit && i == up, st, 0, bas);
else res += dfs(pos - 1, state && i == num[st - pos], limit && i == up, st, 0, bas);
}
}
if(!limit) dp[pos][st][state][bas] = res;
return res;
}
ll solve(ll x, int bas) {
len = 0;
while(x) {
w[len++] = x % bas;
x /= bas;
}
return dfs(len - 1, 1, 1, len - 1, 1, bas);
}
int main() {
int T;
int nn = 1;
ll l, r, L, R;
ll ans;
memset(dp, -1, sizeof(dp));
scanf("%d", &T);
while(T--) {
scanf("%lld %lld %lld %lld", &L, &R, &l, &r);
ans = 0;
for(int i = l; i <= r; i++)
ans += solve(R, i) - solve(L - 1, i);
printf("Case #%d: %lld\n", nn++, ans);
}
return 0;
}